小智 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)
Kei*_*thS 47
基本上,async和await关键字允许您指定方法的执行应在所有用法处停止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
退出做工作()
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的博客系列.