线程与线程池
使用新线程和使用线程池中的线程有什么区别? 有什么性能优势,为什么我应该考虑使用池中的线程,而不是我明确创build的线程? 我在这里专门讨论.NET,但一般的例子都很好。
线程池将为频繁和相对较短的操作提供好处
- 重用已经创build的线程而不是创build新线程(一个昂贵的过程)
-
当有新的工作项目的突发请求时,限制线程创build的速度(我相信这只是在.NET 3.5中)
-
如果排队100个线程池任务,它将只使用与已经创build的线程一样多的线程来处理这些请求(比如说10)。 线程池会进行频繁的检查(我相信3.5 SP1中每500ms),如果有任务排队,将会创build一个新的线程。 如果你的任务很快,那么新线程的数量就会很less,重复使用10个左右的线程将比前面创build100个线程要快。
-
如果您的工作负载始终有大量的线程池请求进入,那么线程池将通过上述过程在池中创build更multithreading,从而将自己调整到您的工作负载,以便有更多的线程可用于处理请求
-
在这里查看关于线程池如何在引擎下工作的深入信息
-
如果工作的时间相对较长(可能是一两秒钟,但取决于具体情况),那么自己创build一个新线程将会更加合适,
@Krzysztof – 线程池线程是当主线程结束时将停止的后台线程。 手动创build的线程默认为前景(在主线程结束后将继续运行),但在调用“启动”之前可以设置为后台。
.NETpipe理的线程池: –
- 根据当前的工作负载和可用的硬件来调整自身的大小
- 包含工作线程和完成端口线程(专门用于服务IO)
- 针对大量相对短暂的操作进行了优化
其他线程池实现存在,可能更适合长时间运行的操作。
具体来说,使用线程池来防止您的应用程序创build太多的线程。 线程池的最重要的function是工作队列。 也就是说,一旦你的机器足够繁忙,线程池将排队请求,而不是立即产生更多的线程。
所以,如果你将创build一个小的,有限的线程数自己创build它们。 如果不能预先确定可以创build多less个线程(例如,它们是为了响应传入的IO而创build的),并且他们的工作将是短暂的,那么使用线程池。 如果你不知道有多less,但是他们的工作将会长期运行,那么平台中没有任何东西可以帮助你 – 但是你也许能够find合适的替代线程池实现。
也
new Thread().Start()
产生前景线程,如果你closures程序不会死的。 线程池线程是closures应用程序时死亡的后台线程。
在这里检查一下早期的主题:
什么时候不应该在.Net中使用ThreadPool?
总结一下,如果你需要产生许多短命的线程,那么Threadpool是很好的,而使用线程则会给你更多的控制权。
我对这些相关的资源使用情况很好奇,并且在我的2012双核英特尔i5笔记本电脑上运行.net 4.0版本,在Windows 8上构build了一个基准testing。线程池平均花费了0.035ms,开始时线程的平均值为5.06女士。 换句话说,对于大量短暂线程,池中的线程启动速度大约快300倍。 至less在testing的范围(100-2000)线程中,每个线程的总时间似乎非常稳定。
这是基准的代码:
for (int i = 0; i < ThreadCount; i++) { Task.Run(() => { }); } for (int i = 0; i < ThreadCount; i++) { var t = new Thread(() => { }); t.Start(); }
线程本地存储不是线程池的好主意。 它给线程一个“身份”; 不是所有的线程都是平等的。 现在,线程池特别有用,如果你只需要一堆相同的线程,就可以在没有创build开销的情况下做好你的工作。
如果你需要很多的线程,你可能需要使用一个ThreadPool。 他们重新使用线程节省了线程创build的开销。
如果你只需要一个线程来完成某个任务,线程可能是最简单的。
线程池线程的主要需求是处理预计几乎立即完成的短小任务。 硬件中断处理程序通常运行在不适合非内核代码的堆栈上下文中,但硬件中断处理程序可能会发现应该尽快运行用户模式I / O完成callback。 为了运行这样的事情创build一个新的线程将是巨大的矫枉过正。 有几个预先创build的线程可以分派来运行I / O完成callback或其他类似的东西是更有效的。
这样的线程的一个关键方面是,如果I / O完成方法总是基本上立即完成并且永远不会被阻塞,并且当前正在运行这样的方法的这样的线程的数量至less等于处理器的数量,则任何其他线程如果其他方法块之一或其执行时间超过正常线程时间片,则可以在上述方法之一之前运行; 如果按照预期使用线程池,则这两者都不应该经常发生。
如果一个方法在开始执行时不能在100ms左右的时间内退出,那么该方法应该通过主线程池以外的其他方法来执行。 如果有一些任务是CPU密集型但不会阻塞的,那么使用独立于“主”线程池的应用程序线程池(每个CPU核心一个线程)来分派它们会很有帮助,因为使用运行非阻塞CPU密集型任务时,比内核多的线程会适得其反。 但是,如果一个方法需要花费一秒或更长时间才能执行,并且大部分时间都会被阻塞,那么这个方法应该可以在专用线程中运行,而且几乎肯定不会在主线程池中运行。 如果一个长时间运行的操作需要通过I / Ocallback来触发,那么应该在callback之前为长时间运行启动一个线程,并在callback脉冲的监视器上等待,否则有callback启动一个新的线程执行操作,而callback退出,有效地返回自己的线程到线程池。
一般来说(我从来没有使用.NET),线程池将用于资源pipe理的目的。 它允许将约束configuration到您的软件中。 这也可能是出于性能原因,因为创build新线程可能是昂贵的。
可能还有系统特定的原因。 在Java中(我不知道这是否适用于.NET),线程的pipe理器可能会应用线程特定的variables,因为每个线程都从池中取出,并在返回时取消设置它们(常见的方法是传递类似于身份)。
示例约束:我只有10个数据库连接,所以我只允许10个工作线程访问数据库。
这并不意味着你不应该创build自己的线程,但有条件下使用一个池是有意义的。
如果您不知道或无法控制将创build多less个线程,则使用池是一个好主意。
只是有一个问题,使用线程来更新列表控件的positionchanged事件(避免freez)上的数据库中的某个字段。 我的用户需要5分钟才能从数据库中得到一个错误(与Access连接太多),因为他正在改变列表的位置太快了…
我知道还有其他解决基本问题的方法(包括不使用访问),但是共享是一个好的开始。