多线程实现Thread.Start()与ThreadPool.QueueUserWorkItem两种方式对比
Thread.Start(),ThreadPool.QueueUserWorkItem都是在实现多线程并行编程时常用的方法。两种方式有何异同点,而又该如何取舍?
写一个Demo,分别用两种方式实现。观察各自的现象。
一个WorkMan class,其内的method doSomething()是每次异步线程调用的方法。该方法只是随机的让线程休眠一段时间。
public void doSomething() { OnBegin(new EventArgs()); // someone does something here var r = new Random(); int sleepTime = r.Next(3000, 180000); Thread.Sleep(900000); OnCompleted(new EventArgs()); } doSomething
Thread.Start()方式实现
workThreads = new Thread[NUMBER_OF_THREADS]; for (var i = 0; i < NUMBER_OF_THREADS; i++) { arrWorkMen[i] = new WorkMan() { WorkStarted = true, InstanceID = startThreadNumber }; arrWorkMen[i].BeginHandler += HandleTaskBegin; arrWorkMen[i].CompletedHandler += HandleTaskCompleted; // create a thread and attach to the object var st = new ThreadStart(arrWorkMen[i].doSomething); workThreads[i] = new Thread(st); startThreadNumber++; } for (var i = 0; i < NUMBER_OF_THREADS; i++) { Thread.Sleep(2000); workThreads[i].Start(); } Thread.Start()
ThreadPool.QueueUserWorkItem方式实现
for (var i = 0; i < NUMBER_OF_THREADS; i++) { arrWorkMen[i] = new WorkMan() { WorkStarted = true, InstanceID = startThreadNumber }; arrWorkMen[i].BeginHandler += HandleTaskBegin; arrWorkMen[i].CompletedHandler += HandleTaskCompleted; startThreadNumber++; } for (var i = 0; i < NUMBER_OF_THREADS; i++) { Thread.Sleep(2000); ThreadPool.QueueUserWorkItem(o => arrWorkMen[i].doSomething()); } ThreadPool.QueueUserWorkItem
观察两种方式下,线程创建和回收的情况。
同样的场景,每2秒钟发起一新的线程,且每一线程均休眠2分钟。Thread.Start()实现下,线程一路最高飙升到71个,然后随着2分钟后休眠线程的结束,线程个数始终在70、71之间徘徊。而ThreadPool.QueueUserWorkItem的实现下,线程个数到达最高73后,始终在72、73之间徘徊。
总体来说,做同样的事情。ThreadPool方式产生的线程数略高于Thread.Start()。Thread.Start()产生的线程在完成任务后,很快被系统所回收。而ThreadPool(线程池)方式下,线程在完成工作后会被保留一段时间以备resue。所以,当需求需要大量线程并发工作的时候,不建议使用ThreadPool方式,因为它会保持很多额外的线程。