Task.Run(Foo)和FooAsync()有什么区别?

时间:2019-07-19 07:06:53

标签: .net multithreading asynchronous parallel-processing threadpool

实际上,我在问使用线程运行阻止方法直接运行取消阻止/异步方法有什么区别?

例如GetResponse / GetResponseAsyncExecuteReader / BeginExecuteReader

表面上,这两个程序都没有阻塞,但是原理上有什么区别?我认为这实际上涉及对多线程和异步的真正理解。

谢谢。

1 个答案:

答案 0 :(得分:1)

简而言之: Task.Run会将方法分配给池线程,而异步方法只需要返回一个Task,但除此之外,它还能执行任何操作想要。

详细的答案:

没有任何特定的例子,就不可能说出异步方法会发生什么。它可能会或可能不会在内部使用线程,或者可能会“欺骗”并阻止调用方,就像常规方法最后通过Task.FromResult(myResult)返回内容一样。

实际上Task.Run也具有Func<Task>Func<Task<TResult>>参数的重载,因此,如果您知道异步方法作弊(或者尽管它不使用线程,则您要强制执行它)出于某些充分的理由),那么您甚至可以在Task.Run调用中包装已经异步的方法。

至于具体示例:

  • Task.Run(() => GetResponse(...))立即返回未完成的Task,并安排GetResponse在池线程中执行。线程完成后,任务将完成。
  • GetResponseAsync(...)立即返回未完成的任务,一旦在基础套接字上收到响应,该任务将完成。这次没有池线程。
  • Task.Run(() => ExecuteReader(...)):与第一点相同
  • BeginExecuteReader:这是一个有趣的话题。由于它使用.NET 1.0 IAsyncResult解决方案,因此我们可能认为它只是为Delegate.BeginInvoke调用了ExecuteReader,这将是微不足道的解决方案,并且最终会使用池线程。但是,如果您调查BeginExecuteReaderInternal,您会发现它还在内部使用任务。自从在.NET 4.0中引入任务以来,它一定已经进行了重构。

顺便说一句,您也可以通过IAsyncResult等待TaskFactory方法:

await Task.Factory.FromAsync(BeginExecuteReader(...));

这不会创建任何其他线程(在由Begin...方法创建的线程之上(如果有的话))只是以一种方便的方式将IAsyncResult变成了可等待的Task