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

当前回答

这里有一个快速的控制台程序,让那些遵循。TaskToDo方法是你想让它异步的长期运行的方法。让它以异步方式运行是由TestAsync方法完成的。test loops方法只是运行TaskToDo任务,并异步运行它们。你可以在结果中看到这一点,因为它们在每次运行中完成的顺序不同——当它们完成时,它们会报告给控制台UI线程。简单,但我认为简单的例子比复杂的例子更好地揭示了模式的核心:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}

其他回答

这里所有的答案都使用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";
}

使用它们是否等同于生成后台线程来执行长时间的任务 时间逻辑?

这篇文章MDSN:异步编程与async和await (c#)明确解释:

async和await关键字不会引起额外的线程 创建。异步方法不需要多线程,因为Async 方法不在自己的线程上运行。该方法在电流上运行 对象时,才在线程上使用时间 方法是活动的。

根据我的理解,async和await所做的主要事情之一是使代码易于编写和阅读。

它们是为了让异步代码易于编写和阅读。

这和生成后台线程来执行长时间逻辑是一样的吗?

一点也不。

//我不明白为什么这个方法必须被标记为'async'。

async关键字启用await关键字。所以任何使用await的方法都必须被标记为async。

// DoSomethingAsync()方法在5秒休眠后到达该行。难道不应该立即到达吗?

不会,因为异步方法默认情况下不会在另一个线程上运行。

//是否在后台线程上执行?

No.


你可能会发现我的async/await介绍很有用。官方MSDN文档也非常好(尤其是TAP部分),异步团队还发布了一个很好的FAQ。

当使用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)。