什么是新的C#等待功能呢?

Chr*_*col 82 c# async-await c#-5.0

任何人都可以解释这个await功能的作用吗

小智 61

他们昨天刚刚在PDC上讨论过这个问题!

Await与.NET中的Tasks(并行编程)结合使用.它是下一版.NET中引入的关键字.它或多或少地允许您"暂停"方法的执行以等待Task完成执行.这是一个简短的例子:

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();
Run Code Online (Sandbox Code Playgroud)

  • 为了完整性,我们要补充一点,上面的代码必须包装在一个用async关键字装饰的方法中.一旦遇到第一个await关键字,该方法应立即返回. (20认同)
  • 用你的话来说:它让你"暂停"这个方法,但是应该注意它不会暂停或阻塞线程. (14认同)
  • 听起来很像Thread.Join(). (12认同)
  • 让我想起[COMEFROM](http://en.wikipedia.org/wiki/COMEFROM) (10认同)
  • 什么时候是C#形式的承诺:http://en.wikipedia.org/wiki/Futures_and_promises (2认同)
  • @mlaw:我认为这种区别太多了.它*阻止了执行的概念线程,并且*可能*对应于OS线程 - 但细节取决于调度程序.它确实是一个线程 - 而不是操作系统线程.这不是无关紧要的,但在理解程序流程方面(这些是控制流程结构)并不重要. (2认同)
  • 这个答案有误导性.`await`不会暂停任何内容,如果等待的`Task`仍在运行,它会将其余部分或方法包含在continuation任务中. (2认同)

Kei*_*thS 47

基本上,asyncawait关键字允许您指定方法的执行应在所有用法处停止await,这标记异步方法调用,然后在异步操作完成后恢复.这允许您在应用程序的主线程中调用方法并异步处理复杂的工作,而无需显式定义线程和连接或阻止应用程序的主线程.

可以认为它与yield return生成IEnumerable的方法中的语句有些相似.当运行时命中时yield,它基本上会保存方法的当前状态,并返回被生成的值或引用.下一次在返回对象(由运行时在内部生成)上调用IEnumerator.MoveNext()时,方法的旧状态将恢复到堆栈,然后继续执行下一行,yield return就好像我们从未离开过方法.如果没有此关键字,则必须自定义IEnumerator类型以存储状态并处理迭代请求,其方法确实非常复杂.

同样,标记为async必须至少有一个的方法await.在a上await,运行时将保存当前线程的状态和调用堆栈,进行异步调用,并展开回运行时的消息循环以处理下一条消息并使应用程序保持响应.当异步操作完成时,在下一个调度机会时,用于启动异步操作的调用堆栈将被推回并继续,就像调用是同步的一样.

因此,这两个新关键字基本上简化了异步进程的编码,就像yield return简化了自定义枚举的生成一样.通过几个关键字和一些背景知识,您可以跳过传统异步模式的所有令人困惑且经常容易出错的细节.这几乎不受任何事件驱动的GUI应用程序的影响,如Winforms,Silverlight的WPF.


Anr*_*nri 31

目前接受的答案具有误导性. await没有暂停任何事情.首先,它只能用于标记为async和返回的方法或lambdas , Task或者void如果你不关心Task在这个方法中运行实例.

这是一个例子:

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

输入DoWork().睡眠3
异步任务迭代0
任务状态:WaitingForActivation
等待ENTER
异步任务迭代1
异步任务迭代2
异步任务迭代3
异步任务迭代4
异步任务迭代5
异步任务迭代6
异步任务迭代7
异步任务迭代8
异步任务迭代9
退出做工作()

  • @Servy你在拖我吗? (7认同)
  • 不.我正在努力帮助你改善你的答案. (2认同)
  • @ Anri ......我非常感谢你们的努力.非常感谢!! (2认同)

Tod*_*ier 11

对于.NET中异步编程的新手,这里有一个(完全假的)类比,你可能更熟悉的场景 - 使用JavaScript/jQuery的AJAX调用.一个简单的jQuery AJAX帖子如下所示:

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});
Run Code Online (Sandbox Code Playgroud)

我们在回调函数中处理结果的原因是我们在等待AJAX​​调用返回时不阻塞当前线程.只有当响应准备就绪时,才会触发回调,从而释放当前线程以同时执行其他操作.

现在,如果JavaScript支持await关键字(当然它没有(当然!)),你可以用这个来实现:

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here
Run Code Online (Sandbox Code Playgroud)

这更清晰,但看起来我们引入了同步阻塞代码.但是(假的)JavaScript编译器会将所有内容都接受await并将其连接到回调中,因此在运行时第二个示例的行为与第一个示例相同.

看起来它可能不会为你节省很多工作,但是当遇到异常处理和同步上下文这样的事情时,编译器实际上为你做了很多繁重的工作.有关更多信息,我建议使用常见问题解答,然后阅读Stephen Cleary的博客系列.

  • "之后的一切"=方法的其余部分.编译器有效地重写了方法的其余部分作为回调并且控制立即返回到当前方法的调用者. (2认同)