根据我的理解,async和await所做的主要事情之一是使代码易于编写和阅读-但使用它们是否等于生成后台线程来执行长时间的逻辑?

我目前正在尝试最基本的例子。我内联添加了一些注释。你能给我解释一下吗?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}

当前回答

异步/等待

实际上,Async / Await是一对关键字,它们只是用于创建异步任务回调的语法糖。

举个例子:

public static void DoSomeWork()
{
    var task = Task.Run(() =>
    {
        // [RUNS ON WORKER THREAD]

        // IS NOT bubbling up due to the different threads
        throw new Exception();
        Thread.Sleep(2000);

        return "Hello";
    });

    // This is the callback
    task.ContinueWith((t) => {
        // -> Exception is swallowed silently
        Console.WriteLine("Completed");

        // [RUNS ON WORKER THREAD]
    });
}

上面的代码有几个缺点。错误不会传递,而且很难阅读。 但是Async和Await来帮助我们:

public async static void DoSomeWork()
{
    var result = await Task.Run(() =>
    {
        // [RUNS ON WORKER THREAD]

        // IS bubbling up
        throw new Exception();
        Thread.Sleep(2000);

        return "Hello";
    });

    // every thing below is a callback 
    // (including the calling methods)

    Console.WriteLine("Completed");
}

Await调用必须在Async方法中。这有一些优点:

返回Task的结果 自动创建回调 检查错误并让它们在callstack中冒泡(只适用于callstack中的无等待调用) 等待结果 释放主线程 在主线程上运行回调 使用线程池中的工作线程执行任务 使代码易于阅读 还有更多

注意:Async和Await用于异步调用时不做这些。为此必须使用任务库,如Task. run()。

下面是等待和无等待解决方案之间的比较

这是一个非异步解决方案:

public static long DoTask()
{
    stopWatch.Reset();
    stopWatch.Start();

    // [RUNS ON MAIN THREAD]
    var task = Task.Run(() => {
        Thread.Sleep(2000);
        // [RUNS ON WORKER THREAD]
    });
    // goes directly further
    // WITHOUT waiting until the task is finished

    // [RUNS ON MAIN THREAD]

    stopWatch.Stop();
    // 50 milliseconds
    return stopWatch.ElapsedMilliseconds;
}

这是async方法:

public async static Task<long> DoAwaitTask()
{
    stopWatch.Reset();
    stopWatch.Start();

    // [RUNS ON MAIN THREAD]

    await Task.Run(() => {
        Thread.Sleep(2000);
        // [RUNS ON WORKER THREAD]
    });
    // Waits until task is finished

    // [RUNS ON MAIN THREAD]

    stopWatch.Stop();
    // 2050 milliseconds
    return stopWatch.ElapsedMilliseconds;
}

实际上,你可以不使用await关键字而调用async方法,但这意味着这里的任何异常都会在释放模式下被吞噬:

public static Stopwatch stopWatch { get; } = new Stopwatch();

static void Main(string[] args)
{
    Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
    // 2050 (2000 more because of the await)
    Console.WriteLine("DoTask: " + DoTask() + " ms");
    // 50
    Console.ReadKey();
}

Async和Await并不用于并行计算。它们用于不阻塞主线程。当涉及asp.net或Windows应用程序时,由于网络调用阻塞主线程是一件糟糕的事情。如果你这样做,你的应用程序将得不到响应,甚至崩溃。

查看微软文档以获得更多的例子。

其他回答

异步/等待

实际上,Async / Await是一对关键字,它们只是用于创建异步任务回调的语法糖。

举个例子:

public static void DoSomeWork()
{
    var task = Task.Run(() =>
    {
        // [RUNS ON WORKER THREAD]

        // IS NOT bubbling up due to the different threads
        throw new Exception();
        Thread.Sleep(2000);

        return "Hello";
    });

    // This is the callback
    task.ContinueWith((t) => {
        // -> Exception is swallowed silently
        Console.WriteLine("Completed");

        // [RUNS ON WORKER THREAD]
    });
}

上面的代码有几个缺点。错误不会传递,而且很难阅读。 但是Async和Await来帮助我们:

public async static void DoSomeWork()
{
    var result = await Task.Run(() =>
    {
        // [RUNS ON WORKER THREAD]

        // IS bubbling up
        throw new Exception();
        Thread.Sleep(2000);

        return "Hello";
    });

    // every thing below is a callback 
    // (including the calling methods)

    Console.WriteLine("Completed");
}

Await调用必须在Async方法中。这有一些优点:

返回Task的结果 自动创建回调 检查错误并让它们在callstack中冒泡(只适用于callstack中的无等待调用) 等待结果 释放主线程 在主线程上运行回调 使用线程池中的工作线程执行任务 使代码易于阅读 还有更多

注意:Async和Await用于异步调用时不做这些。为此必须使用任务库,如Task. run()。

下面是等待和无等待解决方案之间的比较

这是一个非异步解决方案:

public static long DoTask()
{
    stopWatch.Reset();
    stopWatch.Start();

    // [RUNS ON MAIN THREAD]
    var task = Task.Run(() => {
        Thread.Sleep(2000);
        // [RUNS ON WORKER THREAD]
    });
    // goes directly further
    // WITHOUT waiting until the task is finished

    // [RUNS ON MAIN THREAD]

    stopWatch.Stop();
    // 50 milliseconds
    return stopWatch.ElapsedMilliseconds;
}

这是async方法:

public async static Task<long> DoAwaitTask()
{
    stopWatch.Reset();
    stopWatch.Start();

    // [RUNS ON MAIN THREAD]

    await Task.Run(() => {
        Thread.Sleep(2000);
        // [RUNS ON WORKER THREAD]
    });
    // Waits until task is finished

    // [RUNS ON MAIN THREAD]

    stopWatch.Stop();
    // 2050 milliseconds
    return stopWatch.ElapsedMilliseconds;
}

实际上,你可以不使用await关键字而调用async方法,但这意味着这里的任何异常都会在释放模式下被吞噬:

public static Stopwatch stopWatch { get; } = new Stopwatch();

static void Main(string[] args)
{
    Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
    // 2050 (2000 more because of the await)
    Console.WriteLine("DoTask: " + DoTask() + " ms");
    // 50
    Console.ReadKey();
}

Async和Await并不用于并行计算。它们用于不阻塞主线程。当涉及asp.net或Windows应用程序时,由于网络调用阻塞主线程是一件糟糕的事情。如果你这样做,你的应用程序将得不到响应,甚至崩溃。

查看微软文档以获得更多的例子。

这里的答案可以作为await/async的一般指导。它们还包含一些关于await/async如何连接的细节。我想和大家分享一些在使用这个设计模式之前应该知道的实践经验。

术语“await”是字面意义上的,所以无论您在哪个线程上调用它,都将在继续之前等待该方法的结果。在前台线程上,这是一个灾难。前台线程承担了构建应用程序的负担,包括视图、视图模型、初始动画,以及其他任何与这些元素捆绑在一起的东西。所以当你等待前台线程时,你会停止应用程序。当什么都没有发生时,用户会一直等待。这提供了一种消极的用户体验。

你当然可以使用各种方法来等待后台线程:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

这些注释的完整代码在https://github.com/marcusts/xamarin-forms-annoyances。参见名为AwaitAsyncAntipattern.sln的解决方案。

GitHub网站还提供了关于此主题的更详细讨论的链接。

async与函数一起使用,使其成为异步函数。await关键字用于同步调用异步函数。await关键字保持JS引擎的执行,直到promise被解决。

我们应该只在需要立即得到结果时使用async & await。也许函数返回的结果将在下一行中使用。

关注这个博客,它用简单的文字写得很好

我想对此发表我的意见,如果任何其他答案包含我将解释的内容,我很抱歉,我读了大部分,但没有找到它,但我可能错过了一些东西。

我看到了很多错误的概念和很多好的解释,只是想解释一下异步与并行编程的区别,我相信这会让事情更容易理解。

当你需要做长时间的计算,处理器密集的工作,你应该选择使用并行编程,如果可能的话,以优化核心的使用。这将打开一些线程并同时处理一些事情。

假设你有一个数字数组,想要对每一个数字进行一些昂贵的长计算。平行是你的朋友。

异步编程在不同的用例中使用。

当你在等待一些不依赖于你的处理器的事情时,它用来释放你的线程,例如IO(写入和读取磁盘),当你执行IO时,你的线程什么都不做,当你等待一个昂贵的查询结果从DB返回时也是一样。

异步方法在线程等待很长时间返回结果时释放线程。这个线程可以被应用程序的其他部分使用(例如,在web应用程序中,它可以处理其他请求),也可以返回操作系统用于其他用途。

当您的结果完成时,相同的线程(或另一个线程)将返回给您的应用程序以继续处理。

在像。net这样的多线程环境中,异步编程不是强制性的(但是个很好的实践),在web应用程序中,其他线程将响应新请求,但如果你是在像nodejs这样的单线程框架中,这是强制性的,因为你不能阻塞你唯一的线程,否则你将无法回答任何其他请求。

总而言之,长处理器密集型计算将从并行编程中受益更多,而不依赖于处理器的长等待时间,如IO或DB查询或对某些API的调用将从异步编程中受益更多。

这就是为什么Entity Framework有一个async api来保存、列表、查找等等…

记住async/await与wait或waitAll不同,上下文不同。Async/await释放线程,是异步编程。wait / waitAll阻塞所有线程(它们没有被释放)来强制并行上下文中的同步…不同的东西…

希望这对某些人有用…

也许我的见解是相关的。Async告诉编译器要特别对待一个函数,这个函数是可挂起/可恢复的,它以某种方式保存状态。Await暂停了一个功能,但也是一种执行纪律的方式,是限制性的;你需要指定你在等待什么,你不能无故挂起,这使得代码更有可读性,也许也更有效率。这就引出了另一个问题。为什么不等待多件事,为什么一次只等待一件事?我相信这是因为这样的模式已经建立起来了,而程序员们遵循的是最小惊讶的原则。这里存在着模棱两可的可能性:您是满足其中一个条件,还是希望所有条件都得到满足,也许只是其中一些?