我一直在努力学习C#中的多线程编程,我感到困惑的时候,最好使用一个线程池与创建自己的线程。 一本书建议使用仅用于小任务的线程池(这意味着什么),但我似乎无法找到任何真正的指引。 什么是一些你在做这个规划决定时使用的考虑?
Answer 1:
如果你有很多需要不断的处理逻辑的任务,你想,要在并行使用进行池+调度。
如果你需要让你的IO相关的任务,同时,如从远程服务器或磁盘访问下载的东西,但需要为此每隔几分钟说一次,然后让你自己的线程,并杀死他们一旦你完成了。
编辑:关于一些注意事项,我使用线程池的数据库访问,物理/仿真,人工智能(游戏),以及脚本任务运行上处理大量的用户定义的任务虚拟机。
通常一池由每个处理器(所以可能现在4)2个线程,但是你可以设置你想要的线程数量,如果你知道你需要多少。
编辑:做你自己的线程的原因是因为环境的变化,(这就是当线程需要交换和退出的过程中,与他们的记忆一起)。 有没用环境的变化,当你不使用你的线程,只是让他们坐在四周,也许有人会说,可以简单地将节目的一半,性能说(说你有3个睡眠线程和2个活动线程)。 因此,如果这些下载线程正等待着他们吃了吨CPU和降温缓存为您的实际应用
Answer 2:
我会建议你使用C#中的线程池以同样的理由为任何其他语言。
当你想限制运行的线程数量或者不想创建和销毁它们的开销,使用线程池。
通过小任务,你读的书是指寿命短的任务。 如果需要十秒建立一个只运行一秒钟一个线程,这是一个地方,你应该使用池(忽略我的实际数字,它是计算的比例)。
否则,你花你的大部分时间创建和销毁线程,而不是简单地做他们打算做的工作。
Answer 3:
下面是.NET中的线程池的一个很好的总结: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx
该职位也有,当你不应该使用线程池,并开始自己的线程,而不是一些点。
Answer 4:
我强烈建议你阅读的这个免费的电子书约瑟夫阿尔巴哈利线程在C#
至少阅读“入门”部分。 电子书提供了一个很好的介绍,并包括了大量的先进线程的信息也是如此。
知道是否要使用线程池仅仅是个开始。 接下来,您将需要确定哪些进入线程池最好的方法适合您的需要:
- 任务并行库(.NET Framework 4.0中)
- ThreadPool.QueueUserWorkItem
- 异步委托
- 的BackgroundWorker
该电子书解释所有这些,并建议何时使用它们与创建自己的线程。
Answer 5:
线程池的目的是减少你的线程之间的上下文切换。 想想看,有几个组成部分运行的进程。 上述组件可创建工作线程。 在你的进程中的线程越多,更多的时间浪费在上下文切换。
现在,如果每个组件被排队的项目到线程池,你将有上下文切换的开销少了很多。
线程池的设计最大化为工作在您的CPU(或CPU核)正在做。 这就是为什么,在默认情况下,线程池旋转起来每个处理器多线程。
有些情况下,你不希望使用线程池。 如果你在我等待/ O,或等待一个事件,然后等你占用线程池中的线程,它不能被其他人使用。 同样的想法适用于长时间运行的任务,但什么是长时间运行的任务是主观的。
大同暗黑使得一个好点为好。 纺纱起来线程不是免费的。 这需要时间和他们消耗他们的堆栈空间更多的内存。 线程池将重新使用线程分期偿还这笔费用。
注意:您问到使用线程池线程下载数据或执行磁盘I / O。 你不应该使用这个线程池线程(因为我上面列出的原因)。 相反,使用异步I / O(又名BeginXX和EndXX方法)。 对于一个FileStream
这将是BeginRead
和EndRead
。 对于HttpWebRequest
,这将是BeginGetResponse
和EndGetResponse
。 他们更复杂的使用,但它们执行多线程I / O的正确方法。
Answer 6:
当心有可能阻止对它们的处理的任何显著,可变的或未知的一部分,因为它很容易线程饥饿操作.NET线程池。 考虑使用.NET并行扩展,这提供了良好的数目逻辑抽象超过螺纹操作。 它们还包括一个新的调度,这应该是在线程池的改善。 见这里
Answer 7:
要使用小任务的线程池的一个原因只在于有线程池中的线程数量有限。 如果一个用于长时间那么它停止从正在使用的其他代码的线程。 如果发生这种情况很多次,然后线程池可以成为用完。
使用了线程池可以有微妙的影响 - 一些.NET计时器使用线程池中的线程,并且将不火,例如。
Answer 8:
如果你有一个后台任务将生活很长一段时间,很喜欢你的应用程序的整个生命周期,然后创建自己的线程是一个合理的事情。 如果您有需要在一个线程来完成的短作业,然后使用线程池。
在您创建多个线程的应用程序,创建线程的开销变得很大。 使用线程池创建线程一次,并重新使用它们,这样就避免了线程创建开销。
在我的工作,从创建线程使用线程池的短暂改变线程的应用程序确实通过应用程序的放helpped的。
Answer 9:
对于并发执行单位的最高性能,编写自己的线程池,其中线程对象池是在启动时创建,去阻止(以前暂停),等待一个上下文通过执行一个标准接口运行(对象你的代码)。
关于任务与线程主场迎战.NET线程池这么多的报道未能真正给你你需要的性能决定的。 但是,当你对它们进行比较,线程胜出,尤其是一个线程池。 它们分布在CPU中最好的,他们启动速度更快。
什么应该被讨论的事实是视窗(包括Windows 10)的主执行单元是一个线程和OS上下文切换开销通常是可以忽略不计。 简单地说,我一直没能找到很多这些文章的有说服力的证据,物品是否声称通过保存上下文切换或更好的CPU使用率更高的性能。
现在的一些真实的:
我们大多数人并不需要我们的应用程序是确定的,而我们大多数人没有一个硬敲背景线程,这对于例如往往与开发的操作系统。 我上面写的是不是一个初学者。
那么,什么可能是最重要的是要讨论的是什么是很容易编程。
如果你创建自己的线程池,你必须写一些文章做,你就需要使用跟踪执行状态予以关注,如何模拟暂停和恢复,以及如何取消执行 - 包括应用程序范围关掉。 您可能还与是否要动态地扩展你的游泳池,也是你的游泳池将产生怎样的容量限制有关。 我可以写在一个小时这样的一个框架,但那是因为我已经做了很多次。
也许写一个执行单元的最简单的方法是使用一个任务。 任务的好处是,你可以创建一个在你的代码开始它在线(虽然谨慎可能有必要)。 当你要取消的任务可以通过一个取消标记处理。 同时,它采用的承诺方式链接事件,你可以有它返回一个特定类型的值。 此外,与异步和等待,更多的选择存在,你的代码会更加便携。
从本质上说,了解利弊与任务与线程主场迎战.NET线程池是非常重要的。 如果我需要很高的性能,我将使用线程,我更喜欢用我自己的游泳池。
一个简单的方法来比较是启动512个线程,512个任务和线程池512个线程。 你会发现在开始使用线程的延迟(因此,为什么还要写一个线程池),但所有512个线程将在几秒钟内运行时,任务和线程池.NET线程需要长达几分钟就全部开始。
下面是这样一个试验(具有16 GB的RAM i5四芯)的结果,给每个30秒运行。 执行的代码进行简单的文件I / O的SSD驱动器上。
检测结果
Answer 10:
线程池是伟大的,当你有更多的任务比可用线程来处理。
可以将所有任务添加到一个线程池,并指定可在特定时间运行的线程的最大数量。
看看这个 MSDN上页: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx
Answer 11:
始终使用线程池如果可以的话,工作在抽象可能的最高水平。 线程池隐藏创建和你销毁线程,这通常是一件好事!
Answer 12:
大部分的时间,因为你避免创建线程的昂贵的过程,你可以使用游泳池。
然而,在某些情况下,您可能要创建一个线程。 例如,如果你不使用线程池只有一个,如果你想控制线程的堆栈大小您所创建的线程是长期存在的(以避免消耗共享资源)或例子。
Answer 13:
不要忘了调查后台工作。
我找了很多的情况下,它给了我正是我想没有繁重。
干杯。
Answer 14:
我通常使用的线程池,每当我需要做的只是在另一个线程的东西,当它运行或结束并不真正关心。 喜欢的东西记录或者甚至后台下载一个文件(虽然有更好的方法来做到这一点异步式)。 我用我自己的线程,当我需要更多的控制。 还有什么我发现是使用线程安全的队列(黑客自己)来存储“命令对象”是不错,当我有需要的> 1个线程上运行多个命令。 所以你可以分裂一个XML文件,并把每个元素的队列,然后有多个线程对这些元素进行一些处理工作。 我写了这样一个队列早在UNI(VB.net!),我已经转换为C#。 我已经包括它下面没有特殊原因(此代码可能包含一些错误)。
using System.Collections.Generic;
using System.Threading;
namespace ThreadSafeQueue {
public class ThreadSafeQueue<T> {
private Queue<T> _queue;
public ThreadSafeQueue() {
_queue = new Queue<T>();
}
public void EnqueueSafe(T item) {
lock ( this ) {
_queue.Enqueue(item);
if ( _queue.Count >= 1 )
Monitor.Pulse(this);
}
}
public T DequeueSafe() {
lock ( this ) {
while ( _queue.Count <= 0 )
Monitor.Wait(this);
return this.DeEnqueueUnblock();
}
}
private T DeEnqueueUnblock() {
return _queue.Dequeue();
}
}
}
Answer 15:
我想一个线程池来在核用尽可能少延迟地分配工作,并没有与其他应用程序发挥出色。 我发现.NET线程池的表现并不好,因为它可能是。 我知道我想每个核心一个线程,所以我写了我自己的线程池的替代类。 该代码是作为一个回答另一个问题的StackOverflow 在这里 。
作为原来的问题,线程池是用于破碎重复计算成可并行(假设它们可以并行而不改变结果被执行)被执行部件是有用的。 手册线程管理是一样的用户界面和IO任务非常有用。