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

当前回答

这里所有的答案都使用Task.Delay()或其他内置的异步函数。但下面是我的例子,没有使用这些async函数:

// Starts counting to a large number and then immediately displays message "I'm counting...". 
// Then it waits for task to finish and displays "finished, press any key".
static void asyncTest ()
{
    Console.WriteLine("Started asyncTest()");
    Task<long> task = asyncTest_count();
    Console.WriteLine("Started counting, please wait...");
    task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
    //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
    Console.WriteLine("Finished counting.");
    Console.WriteLine("Press any key to exit program.");
    Console.ReadLine();
}

static async Task<long> asyncTest_count()
{
    long k = 0;
    Console.WriteLine("Started asyncTest_count()");
    await Task.Run(() =>
    {
        long countTo = 100000000;
        int prevPercentDone = -1;
        for (long i = 0; i <= countTo; i++)
        {
            int percentDone = (int)(100 * (i / (double)countTo));
            if (percentDone != prevPercentDone)
            {
                prevPercentDone = percentDone;
                Console.Write(percentDone.ToString() + "% ");
            }

            k = i;
        }
    });
    Console.WriteLine("");
    Console.WriteLine("Finished asyncTest_count()");
    return k;
}

其他回答

除了其他答案,还有await (c#参考)

更具体地说,在包含的例子中,它解释了您的情况

下面的Windows窗体示例说明了await在 异步方法,WaitAsynchronouslyAsync。对比一下它的行为 方法使用waitsynchrontically的行为。没有等待 应用到任务的操作符,waitsynchronize同步运行 尽管在定义中使用了async修饰符,并且调用了 线程。睡在它的身体里。

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}

异步&等待简单的解释

简单的类比

一个人可能会等早班火车。这就是他们所做的一切,因为这是他们目前正在执行的主要任务。(同步编程(你通常做的事情!))

另一些人可能在等早班火车的时候,抽着烟,喝着咖啡。(异步编程)

什么是异步编程?

异步编程是指程序员选择在与主线程执行分开的线程上运行一些代码,然后在执行完成时通知主线程。

async关键字实际上做什么?

在方法名前加上async关键字,例如

async void DoSomething(){ . . .

允许程序员在调用异步任务时使用await关键字。这就是它所做的。

为什么这很重要?

在许多软件系统中,主线程专门用于与用户界面相关的操作。如果我正在运行一个非常复杂的递归算法,需要5秒才能在我的计算机上完成,但我在主线程(UI线程)上运行这个,当用户试图单击我的应用程序上的任何东西时,它将出现冻结,因为我的主线程已经排队,目前正在处理太多的操作。因此,主线程无法处理从鼠标点击到从按钮点击运行的方法。

什么时候使用Async和Await?

在不涉及用户界面的情况下,最好使用异步关键字。

假设你正在编写一个程序,允许用户在手机上画草图,但是每隔5秒它就会在互联网上查看天气。

我们应该等待呼叫,轮询每5秒呼叫一次网络以获取天气,因为应用程序的用户需要保持与移动触摸屏的交互以绘制漂亮的图片。

如何使用Async和Await

从上面的例子,下面是一些如何编写它的伪代码:

    //ASYNCHRONOUS
    //this is called using the await keyword every 5 seconds from a polling timer or something.

    async Task CheckWeather()
    {
        var weather = await GetWeather();
        //do something with the weather now you have it
    }

    async Task<WeatherResult> GetWeather()
    {

        var weatherJson = await CallToNetworkAddressToGetWeather();
        return deserializeJson<weatherJson>(weatherJson);
    }

    //SYNCHRONOUS
    //This method is called whenever the screen is pressed
    void ScreenPressed()
    {
        DrawSketchOnScreen();
    }

附加说明-更新

我忘了在我最初的笔记中提到,在c#中,你只能等待被包裹在任务中的方法。例如,你可以等待这个方法:

// awaiting this will return a string.
// calling this without await (synchronously) will result in a Task<string> object.
async Task<string> FetchHelloWorld() {..

你不能等待不是任务的方法,像这样:

async string FetchHelloWorld() {..

请随意查看Task类的源代码。

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

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

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

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

查看这个小提琴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;
    }   

}

来自输出窗口的跟踪:

这个答案旨在提供一些特定于ASP.NET的信息。

通过在MVC控制器中使用async/await,可以提高线程池的利用率,并实现更好的吞吐量,如下文所述。

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

在web应用程序中看到大量的并发请求 启动或有突发负载(并发性突然增加), 使这些web服务调用异步将增加 应用程序的响应性。异步请求采用 处理同步请求所需的时间相同。例如, 如果一个请求进行了web服务调用,需要两秒钟才能完成 完成后,无论执行与否,请求都需要两秒钟 同步或异步。然而,在异步调用期间, 线程在运行时不会阻塞对其他请求的响应 等待第一个请求完成。因此,异步 请求阻止了请求队列和线程池的增长 调用长时间运行的操作的许多并发请求。