根据我的理解,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;
}

当前回答

查看这个小提琴https://dotnetfiddle.net/VhZdLU(如果可能的话改进它),运行一个简单的控制台应用程序,在同一个程序中显示Task, Task. waitall (), async和await操作符的用法。

这个小提琴应该清楚你的执行周期的概念。

下面是示例代码

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

来自输出窗口的跟踪:

其他回答

public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}

当使用async和await时,编译器在后台生成一个状态机。

下面是一个例子,我希望我能解释一些正在发生的高级细节:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

好的,这里发生了什么:

Task<int> longRunningTask = LongRunningOperationAsync();开始执行LongRunningOperation 独立的工作完成了,假设主线程(线程ID = 1),然后等待longRunningTask到达。 现在,如果longRunningTask还没有完成,它仍在运行,MyMethodAsync()将返回到它的调用方法,因此主线程不会被阻塞。当longRunningTask完成时,来自ThreadPool的线程(可以是任何线程)将返回到MyMethodAsync()之前的上下文中并继续执行(在这种情况下将结果打印到控制台)。

第二种情况是longRunningTask已经完成执行,结果可用。当到达await longRunningTask时,我们已经有了结果,所以代码将继续在同一线程上执行。(在本例中将结果打印到控制台)。当然,对于上面的例子,情况并非如此,其中涉及到Task.Delay(1000)。

回答你的第二个问题-何时使用async -这里有一个相当简单的方法,我们使用:

长时间运行的I/O绑定任务,运行时间超过50ms -使用异步。 长时间运行的cpu绑定任务——使用并行执行、线程等。

解释:当你在做I/O工作时——发送网络请求,从磁盘读取数据等——实际的工作是由“外部”硅(网卡,磁盘控制器等)完成的。一旦工作完成,I/O设备驱动程序将“ping”回操作系统,操作系统将执行你的延续代码,回调等。在此之前,CPU可以自由地做自己的工作(作为奖励,你还可以释放一个线程池线程,这对web应用程序的可伸缩性来说是一个非常好的奖励)

附注:50ms阈值是MS的推荐值。否则,异步所增加的开销(创建状态机、执行上下文等)会消耗掉所有的好处。现在找不到MS的原始文章,但这里也提到了https://www.red-gate.com/simple-talk/dotnet/net-framework/the-overhead-of-asyncawait-in-net-4-5/

说实话,我仍然认为最好的解释是维基百科上关于未来和承诺的解释:http://en.wikipedia.org/wiki/Futures_and_promises

基本思想是,您拥有一个单独的异步执行任务的线程池。使用时。然而,对象承诺它将在某个时间执行操作,并在您请求时给您结果。这意味着当您请求结果并且还没有完成时,它将阻塞,否则将在线程池中执行。

从那里你可以优化事情:一些操作可以异步实现,你可以优化像文件IO和网络通信通过批处理后续请求和/或重新排序它们。我不确定这是否已经在微软的任务框架中-但如果不是,这将是我首先要添加的事情之一。

实际上,您可以在c# 4.0中实现这种未来模式。如果你想知道它到底是如何工作的,我可以推荐这个链接:http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/。但是,如果您自己开始使用它,您将注意到如果您想做所有很酷的事情,您确实需要语言支持——这正是微软所做的。

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

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

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