Introduction
I recall the first time I created a UI in .NET that had to go and get some data from a database, and the amount of data that I fetched was way larger in production that my code assumed it would be in my dumbed down test setup. Guess what happened... my UI froze as soon as it used real data. The reason for this is that the UI thread (i.e., the only thread in my naive UI) was being used to carry out this fetching of data from the backend database. Yikes! Surely there is a better way.
As it turned out, there was. .NET offered (and still does) a wide variety of Threading classes to help with just this sort of situation, such as Thread, BackgroundWorker, ThreadPool etc.
So I got to know and love some of these classes in the System.Threading namespace, and they did make a massive difference to the responsiveness of my application, all cool.
Thing is, some of the code one has to write when doing some of this threading stuff using the System.Threading namespace (from here on in "classic threading") took a lot of work in some cases, and just was not that intuitive at times. Classic threading is well known as the domain of experts; after messing with its quirks for long enough, one can begin to see why... You are like frack, where did that Exception come from, ahhhh I am using a shared data object with multiple threads, aha! This has by the main stay been a mixture of intuition/luck/skill... and not necessarily in equal parts.
Luckily, help is at hand. With .NET 4.0, there is a new kid in town. It is called a Task, which some of you may know is part of the Task Parallel Library (TPL), which is a new collection of very, very useful (and I feel highly intuitive) classes aimed at not only making your parallel programming easier to read, but also offers lighter weight objects when compared to the classic threading alternatives. For example, when a new Thread is started in .NET, there is a whole process that goes with that, such as creating queues, thread local storage, managing the Thread's lifecycle etc. This takes time. OK, so you could use the classic threading ThreadPool, which does allow you to queue up work item delegates directly to the ThreadPool, which means you are not impacted by the overhead of creating a new Thread yourself, as the ThreadPool will manage all new Thread creation etc.
However, even using the classic threading ThreadPool, there were problems in that you could not cancel a work item once it has been queued with the ThreadPool, or get a return result that easily. It just doesn't read that well either. There is an excellent article here on CodeProject that tackles some of these issues: Smart ThreadPool, which is pretty excellent actually. However, the new TPL infrastructure has got all these problems covered, and many many more useful features in my opinion.
A TPL Task actually uses the ThreadPool internally, if you use the default scheduler, which you more than likely will most of the time. The scheduler can be swapped out, and that is something I will be showing in a subsequent article. For the time being, if we assume we are using the default scheduler, Tasks will be allocated threads by the the use of a ThreadPool, which handles the creation of Threads to carry out Tasks, so a lot of the heavy lifting (so to speak) is done behind the scenes for us by TPL.
Read more: Codeproject
QR:
0 comments:
Post a Comment