你必须把Task.Run放在一个方法来使其asynchronous?

我试图了解asynchronous以最简单的forms等待。 我想创build一个非常简单的方法,为了这个例子增加了两个数字,根本没有处理时间,这只是一个例子。

例1:

private async Task DoWork1Async() { int result = 1 + 2; } 

例2:

 private async Task DoWork2Async() { Task.Run( () => { int result = 1 + 2; }); } 

如果我等待DoWork1Async()将代码同步或asynchronous运行?

我是否需要用Task.Run包装同步代码,使该方法等待和asynchronous,以便不阻止UI线程?

我试图找出如果我的方法是一个Task或返回Task<T>我是否需要用Task.Run包装代码使其asynchronous。

愚蠢的问题,我敢肯定,但我看到网上的例子,人们正在等待的代码,没有任何asynchronous内,并没有包裹在Task.RunStartNew

首先,我们来澄清一些术语:“asynchronous”( async )意味着它可能会在调用线程启动之前将控制权交回给调用线程。 在async方法中,这些“收益”点是awaitexpression式。

这与“asynchronous”这个术语有很大不同,因为MSDN文档使用了多年(意思是“在后台线程上执行”)。

为了进一步混淆这个问题, async和“等待”是截然不同的。 有一些async方法的返回types不可等待,许多方法返回不是async等待types。

足够的,他们不是 ; 这是他们什么:

  • async关键字允许使用asynchronous方法(即允许awaitexpression式)。 async方法可能会返回TaskTask<T>或(如果您必须) void
  • 任何遵循某种模式的types都可以等待。 最常见的等待types是TaskTask<T>

所以,如果我们将你的问题重新定义为“如何在后台线程上运行一个可等待的操作”,答案就是使用Task.Run

 private Task<int> DoWorkAsync() // No async because the method does not need await { return Task.Run(() => { return 1 + 2; }); } 

(但这种模式是一个不好的方法,见下文)。

但是,如果你的问题是“如何创build一个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代码依赖于它的awaitexpression式中的“awaitable”。 这些“awaitables”可以是其他的async方法,或者只是返回awaitable的常规方法。 返回Task / Task<T>常规方法可以使用Task.Run在后台线程上执行代码,或者更常见的是可以使用TaskCompletionSource<T>或其一个快捷方式( TaskFactory.FromAsyncTask.FromResult等) 。 我build议在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介绍 ; 最后是一些很好的后续资源。 MSDN文档async也exception好。

在使用asynchronous装饰方法时要记住的最重要的事情之一是至less在方法内部有一个 等待操作符。 在你的例子中,我将使用TaskCompletionSource如下所示进行翻译 。

 private Task<int> DoWorkAsync() { //create a task completion source //the type of the result value must be the same //as the type in the returning Task TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); Task.Run(() => { int result = 1 + 2; //set the result to TaskCompletionSource tcs.SetResult(result); }); //return the Task return tcs.Task; } private async void DoWork() { int result = await DoWorkAsync(); } 

当您使用Task.Run运行一个方法时,Task从线程池中获取一个线程来运行该方法。 所以从UI线程的angular度来看,它是“asynchronous的”,因为它不会阻塞UI线程。这对桌面应用程序来说很好,因为通常不需要很multithreading来处理用户交互。

但是,对于Web应用程序,每个请求都由线程池线程提供服务,因此可以通过保存这些线程来增加活动请求的数量。 经常使用线程池线程来模拟asynchronous操作对于Web应用程序是不可扩展的。

真正的asynchronous不一定涉及使用线程的I / O操作,如文件/数据库访问等。你可以阅读这个来理解为什么I / O操作不需要线程。 http://blog.stephencleary.com/2013/11/there-is-no-thread.html

在你的简单例子中,这是一个纯粹的CPU边界计算,所以使用Task.Run是好的。