使用“异步”时,Threadpool的线程是否被阻止?

时间:2017-02-03 11:55:32

标签: .net threadpool

AFAIK以下是真的:

长时间阻塞线程池的线程并不是一个好主意(因为它们是有限的)。 任务使用线程池的线程,因此是短期的,不是很长的阻塞操作。 异步方法(如实体框架中的FindAsync)返回一个您可以等待(或等待)接收结果的任务。

我不明白:

如果我打电话,例如FindAsync只是创建一个在ThreadPool线程上运行的任务并调用非异步查找方法(阻止ThreadPool线程直到find返回)?或者是否涉及更深层次的操作系统机制,并且在Find方法返回之前不使用ThreadPool线程?

原因:

如果变量1成立,则调用FindAsync方法或自己启动任务并在其中调用Find方法没有区别。

如果变量2成立,则存在差异,因为启动调用Find方法的任务将长期阻止ThreadPool线程,而调用FindAsync则不会。

1 个答案:

答案 0 :(得分:2)

  

长时间阻塞线程池的线程并不是一个好主意(因为它们是有限的)。

线程池将通过注入一个新线程来响应线程的“丢失”,因此长时间阻塞线程池线程并不是特别成问题。 (当然,首先阻止线程池线程会更好。)

  

任务使用线程池的线程,因此是短期的,不是很长的阻塞操作。

仅适用于调度到线程池的委托任务。围绕任务的许多旧(.NET 4时代)文档假设您正在使用在线程池上安排的委托任务,因此这是对一般中的任务的常见误解。

在现代世界中,委派任务更为罕见;承诺任务现在更常见。承诺任务只是充当“信号”,意思是“完成的事情”。有关委派任务和承诺任务的更多信息,请参阅Task OverviewTask status上的博文。

(另外,委派任务可以安排到任何类型的TaskScheduler;它们不仅仅用于线程池任务。)

  

异步方法(如实体框架中的FindAsync)返回一个您可以等待(或等待)接收结果的任务。

这里有一个区别,需要在使用async进行实施的方法和TAP methods*Async结尾并打算与await一起使用的方法之间进行区分。这两者通常在一起,但并非总是如此。

async始终返回Promise Task,而不是Delegate Task。此外,通常期望 *Async方法将返回Promise Task,但有些方法会返回Delegate Tasks。当方法执行此操作时,我将其称为“伪异步”,因为它只是同步阻止另一个线程。

  

如果我打电话,例如FindAsync只是创建一个在ThreadPool线程上运行的任务并调用非异步查找方法(阻止ThreadPool线程直到find返回)?

不是一般情况。 .NET提供的几乎所有*Async方法都返回Promise Tasks。

  

或者是否涉及更深层次的操作系统机制,并且在Find方法返回之前不使用ThreadPool线程?

大多数.NET *Async方法返回的Promise Tasks使用I / O Completion Ports,正如我在文章There Is No Thread中所描述的那样。

  

如果变量1成立,则调用FindAsync方法或自己启动任务并在其中调用Find方法没有区别。

     

如果变量2成立,则存在差异,因为启动调用Find方法的任务将长期阻止ThreadPool线程,而调用FindAsync则不会。

在一般情况下,您希望使用*Async方法,这样可以避免阻塞任何线程。

然而,正如其他人在评论中指出的那样,实体框架的这个特定示例有点复杂。实体框架本身是异步不可知的;它构建在“提供者”之上,可能支持也可能不支持异步。 Microsoft的SqlClient提供程序确实支持异步,因此与SQL Server通信的FindAsync将异步正常工作。但是,其他提供程序可能不会(在撰写本文时,SQLite是不支持异步的公共提供程序),对于这些提供程序,“FindAsync之类的”异步“API实际上是通过阻塞线程池线程来实现的。 / p>

因此,在一般情况下,“变体2”将是真实的;但是对于你FindAsync的特定例子,它们都是正确的。