async
关键字 kind of 告诉编译器方法体应该用作任务体。简单来说,我们可以说这些等同于您的示例:
public static Task Producer() <----- How is a Task object returned?
{
return Task.Run(() =>
{
while (true)
{
m_buffer.SendAsync<Int32>(DateTime.Now.Second).Wait();
Thread.Sleep(1000);
}
});
}
public static Task Consumer() <----- How is a Task object returned?
{
return Task.Run(() =>
{
while (true)
{
Int32 n = m_buffer.ReceiveAsync<Int32>().Wait();
Console.WriteLine(n);
}
});
}
当然,你方法的编译结果会和我的例子完全不同,因为编译器足够聪明,它可以以这种方式生成代码,所以你方法中的一些行将在上下文(线程)上调用,它调用方法和其中一些在背景上下文中。而这实际上是为什么Thread.Sleep(1000);
不推荐在async
方法体中,因为这段代码可以在调用该方法的线程上调用。Task 具有等价物,可以替换Thread.Sleep(1000);
等价物await Task.Delay(1000)
,将在后台线程上调用。如您所见await
,关键字保证您将在后台上下文中调用此调用,并且不会阻塞调用者上下文。
让我们再看一个例子:
async Task Test1()
{
int a = 0; // Will be called on the called thread.
int b = await this.GetValueAsync(); // Will be called on background thread
int c = GetC(); // Method execution will come back to the called thread again on this line.
int d = await this.GetValueAsync(); // Going again to background thread
}
所以我们可以说这将生成代码:
Task Test1()
{
int a = 0; // Will be called on the called thread.
vat syncContext = Task.GetCurrentSynchronizationContext(); // This will help us go back to called thread
return Task.Run(() =>
{
// We already on background task, so we safe here to wait tasks
var bTask = this.GetValueAsync();
bTask.Wait();
int b = bTask.Result;
// syncContext helps us to invoke something on main thread
// because 'int c = 1;' probably was expected to be called on
// the caller thread
var cTask = Task.Run(() => return GetC(), syncContext);
cTask.Wait();
int c = cTask.Result;
// This one was with 'await' - calling without syncContext,
// not on the thread, which calls our method.
var dTask = this.GetValueAsync();
dTask.Wait();
int d = dTask.Result;
});
}
同样,这与您从编译器获得的代码不同,但它应该只是让您了解它是如何工作的。如果您真的想查看生成的库中的内容,请使用IlSpy来查看生成的代码。
另外我真的推荐阅读这篇文章异步编程的最佳实践