C# 使用 Thread.Start 与 QueueUserWorkItem 的优势
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/684640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Advantage of using Thread.Start vs QueueUserWorkItem
提问by Cheeso
In multithreaded .NET programming, what are the decision criteria for using ThreadPool.QueueUserWorkItem versus starting my own thread via new Thread() and Thread.Start()?
在多线程 .NET 编程中,使用 ThreadPool.QueueUserWorkItem 还是通过 new Thread() 和 Thread.Start() 启动我自己的线程的决策标准是什么?
In a server app (let's say, an ASP.NET app or a WCF service) I think the ThreadPool is always there and available. What about in a client app, like a WinForms or WPF app? Is there a cost to spin up the thread pool? If I just want 3 or 4 threads to work for a short period on some computation, is it better to QUWI or to Thread.Start().
在服务器应用程序(比方说,ASP.NET 应用程序或 WCF 服务)中,我认为 ThreadPool 始终存在且可用。在客户端应用程序(例如 WinForms 或 WPF 应用程序)中呢?启动线程池是否需要成本?如果我只想让 3 或 4 个线程在某些计算上短时间工作,那么使用 QUWI 还是使用 Thread.Start() 更好。
采纳答案by CodeMonkeyKing
The ThreadPool is always there, however, there are a finite number of threads allocated to the pool based on the number of processors. For ASP.NET applications, it is generally a bad idea to use Threads unless you really are starting off an Async process and know that there won't be a large number of requests (remember that there are a finite number of threads in the ThreadPool which you share with everything running in your AppDomain and there is a realistic limit on the total number of threads you want to create using new Thread() as well).
ThreadPool 始终存在,但是,根据处理器的数量,分配给池的线程数量是有限的。对于 ASP.NET 应用程序,使用线程通常是一个坏主意,除非您真的启动了一个异步进程并且知道不会有大量的请求(记住线程池中的线程数是有限的)您与 AppDomain 中运行的所有内容共享,并且您想要使用 new Thread() 创建的线程总数也有实际限制)。
For WinForms apps consider using the BackgroundWorker instead of using a Thread or the ThreadPool. It uses the ThreadPool, however, it makes communicating between threads easier on the multi-thread savvy programmer.
对于 WinForms 应用程序,请考虑使用 BackgroundWorker 而不是使用线程或线程池。它使用 ThreadPool,然而,它使多线程精明的程序员更容易在线程之间进行通信。
Updated
更新
Avoid using ThreadPool.QueueUserWorkItemas your app pool could disappear at any time. Move this work outside or use WebBackgrounder if you must.
避免使用ThreadPool.QueueUserWorkItem,因为您的应用程序池可能随时消失。如果必须,将这项工作移到外面或使用 WebBackgrounder。
回答by Cherian
This discussion will interest you
When should I not use the ThreadPool in .Net?
这个讨论会让你感兴趣我什么
时候不应该在 .Net 中使用 ThreadPool?
回答by Jim Mischel
The thread pool is always available in .NET apps, regardless of what kind.
线程池在 .NET 应用程序中始终可用,无论哪种类型。
The cost for starting a thread from the thread pool via ThreadPool.QueueUserWorkItem
will be no more than the cost of starting your own thread, and could be less.
从线程池中启动线程ThreadPool.QueueUserWorkItem
的成本不会超过启动自己的线程的成本,而且可能会更低。
If you just want a few threads for a short period, then use the thread pool. That's what it's for.
如果你只是想在短时间内使用几个线程,那么使用线程池。这就是它的用途。
回答by Brian Rasmussen
If your tasks are short you will most likely see much better performance by scheduling tasks on the thread pool via QueueUserWorkItem or BeginInvoke as you avoid the repeated cost of creating and destroying your own threads.
如果您的任务很短,通过 QueueUserWorkItem 或 BeginInvoke 在线程池上调度任务,您很可能会看到更好的性能,因为您避免了创建和销毁自己的线程的重复成本。
The thread pool obviously pays for creating threads as well, but it reuses the threads, so you don't pay the cost per task.
线程池显然也为创建线程付出了代价,但它重用了线程,因此您无需为每个任务支付成本。
You may also want to take a look at Threading in C#(free ebook).
回答by Daniel Earwicker
If you're creating your own threads, it makes sense to start them on first use and then let them hang around for a while in case you need them again - you make an idle thread wait on an event so you can reactivate it by signaling the event, and after a long enough time elapses, the thread will wake itself and exit, reclaiming the unused resources. By keeping a small number of idle threads ready to be reused, you reduce the overhead of constantly creating and destroying threads (which is significant for sufficiently short-lived operations).
如果您正在创建自己的线程,则在第一次使用时启动它们是有意义的,然后让它们闲置一段时间以防您再次需要它们 - 您可以让空闲线程等待事件,以便您可以通过信号重新激活它事件,经过足够长的时间后,线程将自行唤醒并退出,回收未使用的资源。通过保留少量空闲线程以备重用,您可以减少不断创建和销毁线程的开销(这对于足够短的操作而言非常重要)。
But this is basically what the thread queue already does for you - so you may as well use it. It's a solved problem.
但这基本上是线程队列已经为您所做的 - 所以您也可以使用它。这是一个解决的问题。
A similar debate used to happen in the C++ community about strings, believe it or not. Should we each write our own string class, or should we use std::string
? The answer depends on whether you want to learn how to write a string class, or you're done with that and you want to get on with inventing something new.
信不信由你,C++ 社区中曾经发生过关于字符串的类似辩论。我们应该每个人都编写自己的字符串类,还是应该使用std::string
?答案取决于您是想学习如何编写字符串类,还是已经完成并想继续发明新的东西。
回答by Cheeso
I was gonna make this a comment, but it got too long.
CodemonkeyKing seems to have hit on an important point, though not strongly enough in my opinion.
本来想评论的,结果太长了。
CodemonkeyKing 似乎抓住了一个重要的点,尽管在我看来还不够强烈。
There are lots of criteria you might use to describe code. Will it be used in a long running app or not? Winforms app or not? Is it a Server or client app? library or standalone exe? etc etc.
您可以使用许多标准来描述代码。它是否会在长时间运行的应用程序中使用?Winforms 应用程序与否?它是服务器还是客户端应用程序?库还是独立的exe?等等等等
Seems to me that if your code will run in a standalone app and you have control over all the surrounding code, then you can roll your own thread pool, start your own threads, and measure and manage the cost around thread startup, thread latency, and resource consumption. Or you could use the QUWI, but it won't kill your app either way. You are free to choose.
在我看来,如果您的代码将在独立应用程序中运行并且您可以控制所有周围的代码,那么您可以滚动自己的线程池,启动自己的线程,并测量和管理围绕线程启动、线程延迟的成本,和资源消耗。或者您可以使用 QUWI,但它不会以任何方式杀死您的应用程序。您可以自由选择。
On the other hand if your code is packaged as a library that may be used in a server -in ASP.NET, or maybe in a SQL CLR app, or a WCF Service - then it is a really bad idea to create threads. You need to use QUWI, or some other mechanism that exploits the built-in thread pool (like BackgroundWorker). If it is to be used in client-side apps with other libraries, once again, QUWI is required. Imagine that every library wanting to take advantage of multi-core computers rolled their own threads. There would be complete chaos in apps that used more than a few libraries. Rampant threads, all competing for the same resources. No central coordination of #threads vs # processors.
另一方面,如果您的代码被打包为一个库,可以在服务器中使用——在 ASP.NET 中,或者可能在 SQL CLR 应用程序中,或者 WCF 服务中——那么创建线程是一个非常糟糕的主意。您需要使用 QUWI 或其他一些利用内置线程池的机制(如 BackgroundWorker)。如果要将其与其他库一起用于客户端应用程序,则再次需要 QUWI。想象一下,每个想要利用多核计算机的图书馆都推出了自己的线程。使用多个库的应用程序会完全混乱。猖獗的线程,都在争夺相同的资源。#threads 与 # 个处理器之间没有中央协调。
Good hygeine demandsthat a library, whether it is to be consumed in client apps or server apps, uses the common threadpool, and that means QUWI.
良好的卫生要求库,无论是在客户端应用程序还是服务器应用程序中使用,都使用公共线程池,这意味着 QUWI。
Last thing to realize is this;
最后要意识到的是这一点;
A managed thread is either a background thread or a foreground thread. Background threads are identical to foreground threads with one exception: a background thread does not keep the managed execution environment running. Once all foreground threads have been stopped in a managed process (where the .exe file is a managed assembly), the system stops all background threads and shuts down.
Threads that belong to the managed thread pool (that is, threads whose IsThreadPoolThread property is true) are background threads. All threads that enter the managed execution environment from unmanaged code are marked as background threads. All threads generated by creating and starting a new Thread object are by default foreground threads.
If you use a thread to monitor an activity, such as a socket connection, set its IsBackground property to true so that the thread does not prevent your process from terminating.
托管线程是后台线程或前台线程。后台线程与前台线程相同,但有一个例外:后台线程不保持托管执行环境运行。一旦托管进程(其中 .exe 文件是托管程序集)中的所有前台线程都停止,系统将停止所有后台线程并关闭。
属于托管线程池的线程(即 IsThreadPoolThread 属性为 true 的线程)是后台线程。所有从非托管代码进入托管执行环境的线程都被标记为后台线程。默认情况下,通过创建和启动新 Thread 对象生成的所有线程都是前台线程。
如果您使用线程来监视活动(例如套接字连接),请将其 IsBackground 属性设置为 true,以便该线程不会阻止您的进程终止。
from the MSDN site.
来自MSDN 站点。
回答by wallismark
Here's another advantage to using ThreadPool.QueueUserWorkItem.
这是使用 ThreadPool.QueueUserWorkItem 的另一个优势。
I have a winforms app which has a hearbeat. I originally implemented this using
我有一个有心跳的 winforms 应用程序。我最初使用
heartbeat = new Thread(HeartbeatDoWork);
heartbeat.Start();
Which works fine 98% of the time. However when the app is closed sometimes it doesn't 'die' properly, ie the process is still visible in task manager.
在 98% 的情况下都可以正常工作。但是,当应用程序关闭时,有时它不会正确“死亡”,即该进程在任务管理器中仍然可见。
To be brief, the heartbeat published an event and it was handling the event (CAB pub/sub) where it was 'getting stuck'.
简而言之,心跳发布了一个事件,它正在处理它“卡住”的事件(CAB 发布/订阅)。
The fix was easy, just change to using this
修复很简单,只需更改为使用此
ThreadPool.QueueUserWorkItem(HeartbeatDoWork);
I'm sure there's a few extra things I could do when spinning off my own thread and it to would be cleaned up properly, but this is simpler, faster and easier to understand...the ThreadPool does all the work for me.
我确信在分离我自己的线程时我可以做一些额外的事情并且它会被正确清理,但这更简单,更快,更容易理解......线程池为我完成了所有工作。
回答by Marcel
One advantage of using Thread.Start()
is, that you are able to intentionally abortthe thread later. In the ThreadPool
you have no means of controlling the thread execution after you enqueued it.
使用的一个好处Thread.Start()
是,您可以稍后有意中止线程。在ThreadPool
您将线程排入队列后,您无法控制它的执行。
回答by Steve
Most of my reading agrees with Marcel, the ability to control thread if something goes (Abort ...) is something that should be heavily considered particularly if you are dealing with 3rd party calls over which you have no control and may hang.
我的大部分阅读都同意 Marcel 的观点,如果发生某些事情(中止...),那么控制线程的能力应该被认真考虑,特别是如果您正在处理您无法控制并且可能挂起的 3rd 方调用。