使用 "Async" 方法时,线程池的线程是否被阻塞?
When using "Async" Methods are there Threads of the Threadpool blocked?
据我所知,以下内容为真:
长时间阻塞线程池的线程不是一个好主意(因为它们是有限的)。
任务使用线程池的线程,因此是短期的,而不是长期的阻塞操作。
异步方法(如 Entity Framework 中的 FindAsync)return 您可以等待(或等待)接收结果的任务。
不明白的地方:
如果我打电话给FindAsync 是否只是创建了一个在 ThreadPool 线程上运行并调用非异步查找方法的任务(阻塞 ThreadPool 线程直到找到 returns)?或者是否涉及更深层次的操作系统机制并且在 Find 方法之前没有使用 ThreadPool Thread Returns?
原因:
如果变体 1 成立,则调用 FindAsync 方法或自己启动任务与调用其中的 Find 方法没有区别。
如果变体 2 成立,则存在差异,因为启动任务调用 Find 方法将长期阻塞 ThreadPool 线程,而调用 FindAsync 则不会。
It is not a good idea to block a thread of the threadpool for a long time (because they are limited).
线程池将通过注入新线程来响应线程的“丢失”,因此长时间阻塞线程池线程并不是特别有问题。 (当然,最好不要首先阻塞一个线程池线程。
Tasks use threads of the threadpool and are therefore for short term, not long blocking actions.
这仅适用于调度到线程池的委托任务。许多有关任务的旧(.NET 4 时代)文档都假设您使用的是在线程池上安排的委托任务,因此这是对任务的常见误解 通常 。
在现代世界中,委派任务要少得多;如今,Promise Tasks 更为常见。 Promise Tasks 只是一个“信号”,意思是“某事已完成”。有关委派任务和承诺任务的更多信息,请参阅我在 Task Overview and Task status.
上的博客文章
(此外,委派任务 可以 安排到任何类型的 TaskScheduler
;它们不仅仅用于线程池任务。
Async methods (like FindAsync in Entity Framework) return a task you can wait (or await) for to receive the result.
这里需要区分使用 async
实现的方法和 TAP methods 以 *Async
结尾并打算与 [=13 一起使用的方法=].这两者通常在一起,但并非总是如此。
async
总是 return 承诺任务,永远不会是委托任务。此外,通常 预期 *Async
方法将 return Promise 任务,但有些方法 return 委托任务。当方法这样做时,我称之为“假异步”,因为它只是同步地阻塞另一个线程。
If I call e.g. FindAsync is there simply a task created that runs on a ThreadPool thread and invokes the non async find method (blocking the ThreadPool Thread until the find returns)?
一般情况下不会。 .NET return Promise Tasks.
提供的几乎所有 *Async
方法
Or are there deeper operating system mechanisms involved and a ThreadPool Thread is used not before the Find method Returns?
由大多数 .NET *Async
方法编辑的 Promise 任务 return 在幕后使用 I/O 完成端口,正如我在文章 There Is No Thread 中描述的那样。
If variant 1 holds true, there is no difference between calling the FindAsync method or starting a task myself and calling the Find method in it.
If variant 2 holds true, there is a difference, because starting a task calling the Find method will long term block a ThreadPool Thread, while calling FindAsync will not.
在一般情况下,您希望使用 *Async
方法,这样可以完全避免阻塞任何线程。
但是,正如其他人在评论中指出的那样,Entity Framework 的这个特定示例有点复杂。 Entity Framework本身就是async-agnostic;它建立在“提供者”之上,可能支持也可能不支持异步。 Microsoft 的 SqlClient 提供程序确实支持异步,因此 FindAsync
与 SQL 服务器通信将以异步方式正常工作。然而,其他提供者可能不会(在撰写本文时,SQLite 是一个不支持异步的常见提供者),对于那些提供者,像 FindAsync
这样的“异步”API 实际上是通过阻塞一个线程池线程。
因此,在一般情况下,“变体 2”是正确的;但是对于您的 FindAsync
的特定示例,它们都是正确的。
据我所知,以下内容为真:
长时间阻塞线程池的线程不是一个好主意(因为它们是有限的)。 任务使用线程池的线程,因此是短期的,而不是长期的阻塞操作。 异步方法(如 Entity Framework 中的 FindAsync)return 您可以等待(或等待)接收结果的任务。
不明白的地方:
如果我打电话给FindAsync 是否只是创建了一个在 ThreadPool 线程上运行并调用非异步查找方法的任务(阻塞 ThreadPool 线程直到找到 returns)?或者是否涉及更深层次的操作系统机制并且在 Find 方法之前没有使用 ThreadPool Thread Returns?
原因:
如果变体 1 成立,则调用 FindAsync 方法或自己启动任务与调用其中的 Find 方法没有区别。
如果变体 2 成立,则存在差异,因为启动任务调用 Find 方法将长期阻塞 ThreadPool 线程,而调用 FindAsync 则不会。
It is not a good idea to block a thread of the threadpool for a long time (because they are limited).
线程池将通过注入新线程来响应线程的“丢失”,因此长时间阻塞线程池线程并不是特别有问题。 (当然,最好不要首先阻塞一个线程池线程。
Tasks use threads of the threadpool and are therefore for short term, not long blocking actions.
这仅适用于调度到线程池的委托任务。许多有关任务的旧(.NET 4 时代)文档都假设您使用的是在线程池上安排的委托任务,因此这是对任务的常见误解 通常 。
在现代世界中,委派任务要少得多;如今,Promise Tasks 更为常见。 Promise Tasks 只是一个“信号”,意思是“某事已完成”。有关委派任务和承诺任务的更多信息,请参阅我在 Task Overview and Task status.
上的博客文章(此外,委派任务 可以 安排到任何类型的 TaskScheduler
;它们不仅仅用于线程池任务。
Async methods (like FindAsync in Entity Framework) return a task you can wait (or await) for to receive the result.
这里需要区分使用 async
实现的方法和 TAP methods 以 *Async
结尾并打算与 [=13 一起使用的方法=].这两者通常在一起,但并非总是如此。
async
总是 return 承诺任务,永远不会是委托任务。此外,通常 预期 *Async
方法将 return Promise 任务,但有些方法 return 委托任务。当方法这样做时,我称之为“假异步”,因为它只是同步地阻塞另一个线程。
If I call e.g. FindAsync is there simply a task created that runs on a ThreadPool thread and invokes the non async find method (blocking the ThreadPool Thread until the find returns)?
一般情况下不会。 .NET return Promise Tasks.
提供的几乎所有*Async
方法
Or are there deeper operating system mechanisms involved and a ThreadPool Thread is used not before the Find method Returns?
由大多数 .NET *Async
方法编辑的 Promise 任务 return 在幕后使用 I/O 完成端口,正如我在文章 There Is No Thread 中描述的那样。
If variant 1 holds true, there is no difference between calling the FindAsync method or starting a task myself and calling the Find method in it.
If variant 2 holds true, there is a difference, because starting a task calling the Find method will long term block a ThreadPool Thread, while calling FindAsync will not.
在一般情况下,您希望使用 *Async
方法,这样可以完全避免阻塞任何线程。
但是,正如其他人在评论中指出的那样,Entity Framework 的这个特定示例有点复杂。 Entity Framework本身就是async-agnostic;它建立在“提供者”之上,可能支持也可能不支持异步。 Microsoft 的 SqlClient 提供程序确实支持异步,因此 FindAsync
与 SQL 服务器通信将以异步方式正常工作。然而,其他提供者可能不会(在撰写本文时,SQLite 是一个不支持异步的常见提供者),对于那些提供者,像 FindAsync
这样的“异步”API 实际上是通过阻塞一个线程池线程。
因此,在一般情况下,“变体 2”是正确的;但是对于您的 FindAsync
的特定示例,它们都是正确的。