My question is, when should I and when should I not thread?
Can anyone give some general rules?
Say I have an mainForm, and I want to do some business in another thread.
Should I:
- Create a new thread, like
Thread t = new Thread(new ThreadStart(ThreadProc)); - Declare an delegate, like
myDelegate.BeginInvoke(IsyncCallback)(delegate, not control, yes 🙂 - Create a
System.ComponentModel.BackgroundWorker()
for the best performance?
Example scenarios:
- Fetch data from database to control, or serious background calculation
- Maybe multi threads if it’s something like an ATM
- A thread you want to stay alive forever
And please, give me deep explanations, not like ‘I guess’ 🙂
What business is the new thread doing, you may ask? That’s why I want some general rules, it might differ.
Thanks!
You should pick from these options not because of performance, but because of the facilities they provide.
Out of those options,
BackgroundWorkerhas the best facilities.This can increase performance due to the system not having to spawn new threads to satisfy your request, but instead allocating from an existing pool of threads.
The other two options don’t have quite as nice facilities built in. In a nicely implemented UI application, you’d have to build them yourself, and I don’t think most people would do much better perf-wise than the implementations for
BackgroundWorkerwithout a lot of work.You might also want to consider the Task Parallel Library in .Net 4.0 and above. It supports cancellation, more direct integration into the language, chained and dependent tasks, and other interesting features.
Thread is the original construct out of all these. It provides basic threading support in .Net. It is low level and should be avoided unless you don’t have a better option that fits your needs.
Delegate.BeginInvoke is a hook for allowing someone to create a task-based threading library. Someone can pass that library a delegate, or that library could store a list of delegates. From these it would call
BeginInvokeon them to spawn threads. These threads are allocated from a thread pool. This is a building block, though at a higher level thanThread. There are higher level facilities you probably want to use.BackgroundWorker is the most user friendly out of these options. It is most useful for UI (GUI or command line) applications where you want to provide the user feedback about the status of a specific background task. It also supports cooperative cancellation. Both of these things are extremely common.
There are other facilities you didn’t mention, like using thread pools directly, or the task parallel library. Those are suited to yet other tasks, and are worth a look and consideration.
People cannot guess perf for code they cannot run. As a general rule for thread perf, you probably shouldn’t be concerned about it unless you’re writing an extremely processor intensive algorithm. And then you should usually be concerned with your algorithm and making it fully parallelizable before worrying about low level details like perf of the thread facility.
You should definitely profile your code to determine the bottlenecks in your codebase and see if you can improve them. You can’t preempt profiling with a set of programming rules.
DB fetch is IO bound, not CPU bound. This is a case where you’re threading to wait on a background task, not threading to maximize CPU usage. Don’t worry about thead perf in such a scenario.