Recently when being interviewed, I got this question.
Q: Have you written multithreaded applications?
A: Yes
Q: Care to explain more?
A: I used Tasks
(Task Parallel library) to carry out some tasks like waiting for some info from internet while loading UI
. This improves my application usability.
Q: But, just you have used TPL
means that you have written an multithreaded
application?
Me: (Not sure what to say1)
So, whats exactly a multi-threaded application? Is it different from using Tasks
?
A new Thread()is not dealing with Thread pool thread, whereas Task does use thread pool thread. A Task is a higher level concept than Thread.
Threading. Tasks namespaces. The purpose of the TPL is to make developers more productive by simplifying the process of adding parallelism and concurrency to applications. The TPL scales the degree of concurrency dynamically to most efficiently use all the processors that are available.
Thread-Pool pattern states, the work items are queued and the free threads in thread pool takes one from this queue. TPL however store the items (tasks) to queues of threads and work-stealing works if needed... Thus, quite differently.
Using the Task Parallel Library in . NET 4.0The concept of following more than one thread at a time introduces the subject of multi-tasking and multi-threading. An application has one or more processes in it. Think of a process as a program running on your computer. Now each process has one or more threads.
Tasks can be used to represent operations taking place on multiple threads, but they don't have to. One can write complex TPL applications that only ever execute in a single thread. When you have a task that, for example, represents a network request for some data, that task is not going to create additional threads to accomplish that goal. Such a program is (hopefully) asynchronous, but not necessarily mutlithreaded.
Parallelism is doing more than one thing at the same time. This may or may not be the result of multiple threads.
Let's go with an analogy here.
Here is how Bob cooks dinner:
Bob has cooked entirely synchronously with no multithreading, asynchrony, or parallelism when cooking his dinner.
Here is how Jane cooks dinner:
Jane leveraged asynchronous cooking (without any multithreading) to achieve parallelism when cooking her dinner.
Here is how Servy cooks dinner:
Servy leveraged multiple threads (workers) who each individually did their work synchronously, but who worked asynchronously with respect to each other to achieve parallelism.
Of course, this becomes all the more interesting if we consider, for example, whether our stove has two burners or just one. If our stove has two burners then our two threads, Bob and Jane, are both able to do their work without getting in each others way, much. They might bump shoulders a bit, or each try to grab something from the same cabinet every now and then, so they'll each be slowed down a bit, but not much. If they each need to share a single stove burner though then they won't actually be able to get much done at all whenever the other person is doing work. In that case, the work won't actually get done any faster than just having one person doing the cooking entirely synchronously, like Bob does when he's on his own. In this case we are cooking with multiple threads, but our cooking isn't parallelized. Not all multithreaded work is actually parallel work. This is what happens when you are running multiple threads on a machine with one CPU. You don't actually get work done any faster than just using one thread, because each thread is just taking turns doing work. (That doesn't mean multithreaded programs are pointless on one cores CPUs, they're not, it's just that the reason for using them isn't to improve speed.)
We can even consider how these cooks would do their work using the Task Parallel Library, to see what uses of the TPL correspond to each of these types of cooks:
So first we have bob, just writing normal non-TPL code and doing everything synchronously:
public class Bob : ICook { public IMeal Cook() { Pasta pasta = PastaCookingOperations.MakePasta(); Sauce sauce = PastaCookingOperations.MakeSauce(); return PastaCookingOperations.Combine(pasta, sauce); } }
Then we have Jane, who starts two different asynchronous operations, then waits for both of them after starting each of them to compute her result.
public class Jane : ICook { public IMeal Cook() { Task<Pasta> pastaTask = PastaCookingOperations.MakePastaAsync(); Task<Sauce> sauceTask = PastaCookingOperations.MakeSauceAsync(); return PastaCookingOperations.Combine(pastaTask.Result, sauceTask.Result); } }
As a reminder here, Jane is using the TPL, and she's doing much of her work in parallel, but she's only using a single thread to do her work.
Then we have Servy, who uses Task.Run
to create a task that represents doing work in another thread. He starts two different workers, has them each both synchronously do some work, and then waits for both workers to finish.
public class Servy : ICook { public IMeal Cook() { var bobsWork = Task.Run(() => PastaCookingOperations.MakePasta()); var janesWork = Task.Run(() => PastaCookingOperations.MakeSauce()); return PastaCookingOperations.Combine(bobsWork.Result, janesWork.Result); } }
A Task
is a promise for future work to be completed. When using it, you can use it for I/O based
work, which does not require you to be using multiple threads for code execution. A good example is using C# 5's feature of async/await
with HttpClient
which does network based I/O work.
However, you can take advantage of the TPL
to do multithreaded work. For example, when using Task.Run
or Task.Factory.Startnew
to start a new task, behind the scenes work gets queued for you on the ThreadPool
, which the TPL
abstracts away for us, allowing you to use multiple threads.
A common scenario for using multiple threads is when you have CPU bound work which can be done simultaneously (in parallel). Working with a multithreaded application comes with great responsibility.
So we see that working with the TPL
dosen't necasserly mean using multiple threads, but you definitely can leverage it to do multithreading.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With