如果你在一个不在线程池中的线程中等待会发生啥?

Posted

技术标签:

【中文标题】如果你在一个不在线程池中的线程中等待会发生啥?【英文标题】:What happens if you await in a thread that isn't in the thread pool?如果你在一个不在线程池中的线程中等待会发生什么? 【发布时间】:2021-08-03 09:50:47 【问题描述】:

如果我像这样创建一个新线程:

Thread thread = new Thread(.....);
thread.Start(......);

如果该线程内的方法使用await 运算符会发生什么? 我知道在正常情况下,这会导致 .Net 保存当前执行的状态并将线程返回给线程池,这样它就可以在我们等待等待的方法完成时处理其他事情,但是如果这样呢不是在线程池中的线程开始吗?

【问题讨论】:

这与您在控制台应用程序中执行此操作时相同 - 因为在这两种情况下都没有同步上下文 这是一个理论问题吗?因为无论如何你都不应该这样做。要么使用异步模式,要么使用线程,但不要混合使用。 所以如果我需要运行一些异步代码,我应该使用 .Wait() 来阻止它? 【参考方案1】:

我知道在正常情况下,这会导致 .Net 保存当前执行的状态并将线程返回给线程池,以便它可以在我们等待等待的方法完成时处理其他事情,但是如果这不在线程池线程中怎么办?

到clarify a bit,await 将保存本地状态,然后返回。它不会立即放弃线程。

因此,在这种情况下,如果Thread 的 main 方法返回,则该线程退出。因为不是线程池线程,所以不会返回线程池;它只是退出,因为它的线程进程返回了。

还有其他场景:

如果线程是 UI 线程,则返回到其消息循环。线程继续运行,处理其他消息。 如果线程是控制台应用程序的主线程,则它会退出,从而导致控制台应用程序退出。

如果该线程中的某个方法使用 await 运算符会怎样?

与使用await 的任何其他时间相同:

await 捕获“上下文”(SynchronizationContext.CurrentTaskScheduler.Current)。在这种情况下,上下文将是线程池上下文。 当方法准备好恢复时,它会在该上下文中恢复。

所以在这种情况下,await 将返回,导致线程退出。然后稍后,该方法的其余部分将在线程池线程上运行。

【讨论】:

我的线程方法中使用了一些第三方库。例如,也许我想做一个 http 请求。这些方法都是异步的,所以我可以使用 .Wait() 来确保在 I/O 发生时阻塞当前线程,从而使我的线程保持活动状态,对吗?如果这些库中的底层代码使用异步等待怎么办。如何确保我的线程保持打开状态并且不会退出并在线程池中投入更多工作? @Josh:你为什么要把这些都放在一个特定的线程上? 我在 Web 应用中有一个后台任务。它需要做一系列事情。我曾经有人说这不应该在后台任务中完成,但无论如何,无论我采取哪个方向,上面的问题仍然会困扰我! @Josh:阻塞异步代码会阻塞你的线程,但它也会使用线程池来运行你的线程正在等待的任何延续。因此,它将使用 1-2 个线程而不是 0-1 个线程——通常不是一个好主意。另一种方法是provide your own SynchronizationContext tied to your thread,以便await 将其延续(默认情况下)安排到您自己的线程。但是没有什么可以阻止代码使用ConfigureAwait(false),这意味着它无论如何都会在线程池线程上恢复。 @Josh:我认为根本不需要单独的线程;让线程池完成工作。【参考方案2】:

如果您“创建”线程,则您“管理”它。

一旦计划在该线程上运行的代码完成,该线程将被销毁。

如果您在创建的线程上运行 async/await 代码,您很可能很快就会用完该线程,并付出创建和销毁线程的代价,而没有任何好处。

线程池用于调度短期代码,并且通常使用 async/await。

如果您有一些长时间运行的代码阻塞,那么创建自己的线程可能会更好。

【讨论】:

以上是关于如果你在一个不在线程池中的线程中等待会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

线程池中的可运行与线程内和线程池中的可运行有啥区别

20210601 线程池中的异常处理

20210601 线程池中的异常处理

处理线程池中的优先级

JAVA 线程池 其中一个线程执行失败 则线程重新执行或者重新提交任务 急

如果某些线程比其他线程先结束会发生啥?