AFAIK以下是真的:
长时间阻塞线程池的线程并不是一个好主意(因为它们是有限的)。 任务使用线程池的线程,因此是短期的,不是很长的阻塞操作。 异步方法(如实体框架中的FindAsync)返回一个您可以等待(或等待)接收结果的任务。
我不明白:
如果我打电话,例如FindAsync只是创建一个在ThreadPool线程上运行的任务并调用非异步查找方法(阻止ThreadPool线程直到find返回)?或者是否涉及更深层次的操作系统机制,并且在Find方法返回之前不使用ThreadPool线程?
原因:
如果变量1成立,则调用FindAsync方法或自己启动任务并在其中调用Find方法没有区别。
如果变量2成立,则存在差异,因为启动调用Find方法的任务将长期阻止ThreadPool线程,而调用FindAsync则不会。
答案 0 :(得分:2)
长时间阻塞线程池的线程并不是一个好主意(因为它们是有限的)。
线程池将通过注入一个新线程来响应线程的“丢失”,因此长时间阻塞线程池线程并不是特别成问题。 (当然,首先阻止线程池线程会更好不。)
任务使用线程池的线程,因此是短期的,不是很长的阻塞操作。
仅适用于调度到线程池的委托任务。围绕任务的许多旧(.NET 4时代)文档假设您正在使用在线程池上安排的委托任务,因此这是对一般中的任务的常见误解。
在现代世界中,委派任务更为罕见;承诺任务现在更常见。承诺任务只是充当“信号”,意思是“完成的事情”。有关委派任务和承诺任务的更多信息,请参阅Task Overview和Task 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
的特定例子,它们都是正确的。