是.net任务线程在等待异步操作完成时临时返回池的资源
本文关键字:返回 资源 完成时 任务 net 线程 在等待 异步操作 | 更新日期: 2023-09-27 18:18:02
我有一个TPL任务,它做两件事。首先,它调用web服务。其次,它将一些数据插入数据库。我有多达20个任务一次开始做同样的事情一遍又一遍。他们整天所做的就是调用web服务并将数据插入数据库。
我对。net中的TPL相当陌生。我已经做了一些后台工作进程和异步web服务的东西。
web服务调用和数据库插入都阻塞了Task所在线程内的调用。
我知道在幕后,当你使用任务时,. net为你管理一个线程池。是吗?
如果我使用async和await()进行服务调用和数据库调用,而不是使它们阻塞调用,线程池会有更多的线程可供使用吗?
我的理论(我不确定为什么我认为这一点)是线程在等待阻塞web服务时忙着什么也不做,并且不能暂时将其资源返回到池中。但是我想知道任务是否在等待异步调用完成,主任务线程是否能够切换到让其他东西在等待时处理。
我的理论对吗?还是我在胡编乱造?
我正在使用c#和。net 4.0,但如果需要,我可以使用4.5。
线程池是否有更多的线程可供使用服务调用和数据库调用使用async和await()代替给他们打骚扰电话?
这取决于你所说的"利用async-await"是什么意思。
当您使用Task.Run
时,在幕后,Task
类使用ThreadPool
来使用ThreadPool
线程卸载工作。
如果你的服务没有公开一个真正的异步api,你使用Task.Run
来排队你的工作,你仍然会阻塞一个线程池线程来做IO绑定的工作,不管使用async-await
。在你的问题中,你说两个调用都是阻塞调用,在这种情况下,答案是否定的,用于进行这些阻塞调用的线程池线程仍然会被阻塞。
如果你的服务和数据库调用是真正的异步api(不消耗任何额外的线程来完成它的工作),你可以利用async-await
,当你在其中一个调用上await
时(你不需要使用Task)。使用它们运行),当前线程将把控制权交还给调用者,并可在此期间用于完成更多工作。如果是这样,那么是。
你的理论是正确的。如果排队线程池的主要工作是发出IO绑定请求,那么它的大部分时间都是阻塞,直到请求完成。我的理论(我不确定为什么我认为这一点)是线程在等待阻塞web服务时忙着什么也不做,并且不能暂时将其资源返回到池中。但是我想知道任务是否在等待异步调用完成,主任务线程是否能够切换到让其他东西在等待时处理。
当你await
a Task
时,控制权返回给调用者。让我们假设你的服务调用是一个REST调用,你可以使用HttpClient
,它暴露了真正的非线程消耗异步方法,如GetAsync
, PostAsync
,当你await
这些调用时,你的调用线程被释放,同时做更多的工作。
如果应用程序的所有任务都阻塞,每个任务将使用线程池中的一个线程。
如果所有任务定期await
,则线程池不需要为每个任务使用一个线程。
当你的代码await
是一个尚未完成的操作时,该方法的状态被保存,以便它可以在任何其他线程上恢复。
空闲的线程池线程会在一段时间后被释放,所以当调用await
的方法仍在运行时,遇到await
的实际线程可以从线程池中被释放。
把所有这些放在一起,一个异步版本的例程可以用更少的线程完成同样的工作(假设工作负载在等待时间和旋转CPU之间有足够的平衡)。
这段代码运行100个同步等待的任务:
var numTasks = 100;
for (int i = 0; i < numTasks; i++)
{
Thread.Sleep(5);
Task.Run(() =>
{
Thread.Sleep(5000);
Interlocked.Decrement(ref numTasks);
});
}
while (numTasks > 0) Thread.Sleep(100);
对于异步等待,更改为:
Task.Run(async () =>
{
await Task.Delay(5000);
Interlocked.Decrement(ref numTasks);
});
在我的系统中,异步版本的峰值线程数增加了一半,并且需要20%的时间来完成相同的"工作"。
答案是肯定的。虽然从技术上讲,它不是"等待"异步操作完成(否则async就没有好处了)。在底层有一个回调委托,它在异步操作完成时运行,这允许调用线程在不阻塞的情况下继续。是async/await的魔力把这些"延续"变成了线性的代码。
因为你正在使用一个线程池线程,当它遇到await时,线程将返回到线程池。这里需要注意的是,正常的行为是当等待的操作完成时,它将尝试回到它启动的线程上(现在可能正在被另一个任务使用),因此您可能会观察到获得结果的延迟问题,因为线程池线程现在正在启动其他任务。随着时间的推移,线程池将尝试调整可用线程的数量以满足需求,但如果您的工作是突发的,您可能会发现这不会很快发生。结果将是明显的性能差,因为您可能只有少量的线程可用。