首先,让我们澄清一些术语:“异步”( 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
这些“等待”可以是其他async
方法,也可以只是返回等待的常规方法。Task
返回/的常规方法Task<T>
可用于Task.Run
在后台线程上执行代码,或者(更常见)它们可以使用TaskCompletionSource<T>
或其快捷方式之一(TaskFactory.FromAsync
,Task.FromResult
等)。我不建议将整个方法包装在Task.Run
; 同步方法应该具有同步签名,并且应该由消费者决定是否应该将其包装在 a 中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
介绍;最后是一些很好的后续资源。MSDN 文档async
也非常好。