Thread.Start() versus ThreadPool.QueueUserWorkItem

2019-01-21 05:11发布

问题:

The Microsoft .NET Base Class Library provides several ways to create a thread and start it. Basically the invocation is very similar to every other one providing the same kind of service: create an object representing an execution flow (or more), assign it a delegate representing the execution flow to execute and, eventually, depending on delegate signature, an object as a parameter.

Well, there are two approaches (essentially):

1) Using the System.Threading.Thread class.

Thread curr = new Thread(myfunction); /* In a class, myfunction is a void taking an object */
curr.Start(new Object()); /* Or something else to be downcast */

2) Using the System.Threading.ThreadPool class.

ThreadPool.QueueUserWorkItem(myfunction, new Object()); /* Same philosophy here */

Are there any special reasons why I should use 1) or 2)?

  • Performance reasons?
  • Patterns?
  • What is the best approach?

I have a feeling that the answer is: "Depend by the situation". Could you please list some situations where one approach is better than another?

回答1:

Starting a new thread can be a very expensive operation. The thread pool reuses threads and thus amortizes the cost. Unless you need a dedicated thread, the thread pool is the recommended way to go. By using a dedicated thread you have more control over thread specific attributes such as priority, culture and so forth. Also, you should not do long running tasks on the thread pool as it will force the pool to spawn additional threads.

In addition to the options you mention .NET 4 offers some great abstractions for concurrency. Check out the Task and Parallel classes as well as all the new PLINQ methods.



回答2:

The Managed Thread Pool has some very good guidelines on when NOT to use the thread pool.

In my experience, you want to create your own thread when you need a persistent, dedicated, long-running thread. For everything else, use asynchronous delegates or something like QueueUserWorkItem, BackgroundWorker, or the Task-related features of .NET 4.0.



回答3:

Threads in ThreadPool are background threads; All threads created and started by a new Thread object are foreground threads.

A background thread does not keep the managed execution environment running.

refer to http://msdn.microsoft.com/en-us/library/h339syd0.aspx for more.



回答4:

In .NET 4.5.2 they added a new method: HostingEnvironment.QueueBackgroundWorkItem.

This appears to be an alternative to ThreadPool.QueueUserWorkItem. Both behave similarly, but there are some nice benefits to using the new method when working in ASP.NET:

The HostingEnvironment.QueueBackgroundWorkItem method lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed. This method can't be called outside an ASP.NET managed app domain.



回答5:

Using the ThreadPool, you have less control of the threading system. This is a trade off to simplify the process for you. If you have all that you need from the ThreadPool, you should feel free to utilize it. If you need more control of the threads, then you need to of course use the Thread classes.



回答6:

ThreadPool.QueueUserWorkItem() is basically for fire-and-forget scenarios, when application doesn't depend on whether operations will finish or not.

Use classic threads for fine-grained control.



回答7:

You should use ThreadPool.QueueUserWorkItem except in cases of:

  • You require a foreground thread.

  • You require a thread to have a particular priority.

  • You have tasks that cause the thread to block for long periods of time. The thread pool has a maximum number of threads, so a large number of blocked thread pool threads might prevent tasks from starting.

  • You need to place threads into a single-threaded apartment. All ThreadPool threads are in the multithreaded apartment.

  • You need to have a stable identity associated with the thread, or to dedicate a thread to a task.

Reference link.