首先,让我们澄清一些术语:“异步”(async
)意味着它可以在启动之前将控制权交还给调用线程。在一种async
方法中,那些“屈服”点是await
表达式。
这与“异步”一词有很大不同,因为MSDN文档使用(多年来)表示“在后台线程上执行”。
进一步混淆这个问题,async
与“等待”有很大不同;有一些async
方法的返回类型不可等待,而许多方法的返回类型则不是async
。
足够了他们不是。这里是他们什么是:
- 所述
async
关键字允许异步方法(即,它允许await
表达式)。async
方法可能会返回Task
,Task<T>
或(如果需要)void
。
- 遵循特定模式的任何类型都是可以等待的。最常见的等待类型是
Task
和Task<T>
。
因此,如果我们将您的问题重新表述为“如何以一种可以等待的方式在后台线程上运行操作”,答案是使用Task.Run
:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(但是这种模式是一种糟糕的方法;请参见下文)。
但是,如果您的问题是“我如何创建一种async
可以让其返回给调用者而不是阻止它的方法”,那么答案就是声明该方法async
并将await
其用于“屈服”点:
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
因此,事物的基本模式是使async
代码依赖于其await
表达式中的“ awaitables” 。这些“等待项”可以是其他async
方法,也可以是返回等待项的常规方法。常规方法返回Task
/ Task<T>
可使用Task.Run
到在后台线程执行代码,或(更常见),他们可以用TaskCompletionSource<T>
或它的快捷方式(之一TaskFactory.FromAsync
,Task.FromResult
等等)。我不建议在中包装整个方法Task.Run
。同步方法应具有同步签名,是否应将其包装在Task.Run
:
private int DoWork()
{
return 1 + 2;
}
private void MoreSynchronousProcessing()
{
// Execute it directly (synchronously), since we are also a synchronous method.
var result = DoWork();
...
}
private async Task DoVariousThingsFromTheUIThreadAsync()
{
// I have a bunch of async work to do, and I am executed on the UI thread.
var result = await Task.Run(() => DoWork());
...
}
我的博客上有一个async
/ await
intro;最后是一些很好的后续资源。的MSDN文档async
也非常出色。