NET 4.0 and System.threading

Embed Size (px)

Citation preview

  • 7/27/2019 .NET 4.0 and System.threading

    1/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 1/14

    CodeThinkedby Justin Etheredge

    Pages

    About

    Contact

    Rails 3 Baby StepsCategories

    Back to Basics Series

    Blogging

    Book Review

    C#

    Computers

    Functional Programming Series

    IronRuby via C# Series

    MiscellaneousRuby

    Scala via C# Series

    Screencasts

    Software Design

    Software Development

    SquishIt

    T-SQL Development

    Technical Presenting Series

    TechnologyUncategorized

    Web Development

    RSS

    .NET 4.0 and System.Threading.Tasks

    https://www.codethinked.com/category/web-developmenthttps://www.codethinked.com/category/technologyhttps://www.codethinked.com/category/technical-presenting-serieshttp://www.codethinked.com/category/tsql-developmenthttp://www.codethinked.com/category/squishithttp://www.codethinked.com/category/software-designhttp://www.codethinked.com/category/screencastshttp://www.codethinked.com/category/scala-via-csharp-serieshttp://www.codethinked.com/category/rubyhttp://www.codethinked.com/category/ironruby-via-csharp-serieshttp://www.codethinked.com/category/functional-programming-serieshttp://www.codethinked.com/category/computershttp://www.codethinked.com/category/c-sharphttp://www.codethinked.com/category/blogginghttps://www.codethinked.com/category/back-to-basics-serieshttp://www.codethinked.com/rails-3-baby-steps-serieshttp://www.codethinked.com/abouthttp://www.codethinked.com/http://feeds.feedburner.com/Codethinkedhttps://www.codethinked.com/category/web-developmenthttps://www.codethinked.com/category/uncategorizedhttps://www.codethinked.com/category/technologyhttps://www.codethinked.com/category/technical-presenting-serieshttp://www.codethinked.com/category/tsql-developmenthttp://www.codethinked.com/category/squishithttp://www.codethinked.com/category/software-developmenthttp://www.codethinked.com/category/software-designhttp://www.codethinked.com/category/screencastshttp://www.codethinked.com/category/scala-via-csharp-serieshttp://www.codethinked.com/category/rubyhttp://www.codethinked.com/category/miscellaneoushttp://www.codethinked.com/category/ironruby-via-csharp-serieshttp://www.codethinked.com/category/functional-programming-serieshttp://www.codethinked.com/category/computershttp://www.codethinked.com/category/c-sharphttp://www.codethinked.com/category/book-reviewhttp://www.codethinked.com/category/blogginghttps://www.codethinked.com/category/back-to-basics-serieshttp://www.codethinked.com/rails-3-baby-steps-serieshttp://www.codethinked.com/contacthttp://www.codethinked.com/abouthttp://www.codethinked.com/
  • 7/27/2019 .NET 4.0 and System.threading

    2/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 2/14

    In the soon-to-be-released .NET 4.0 framework and Visual Studio 2010 we are going to get a plethora of new tools to help us write better multi-threaded

    applications. One of these tools is a new namespace within the System.Threading namespace which is called "Tasks". The Tasks in System.Threading.Tasks

    namespace are a method of fine grained parallelism, similar to creating and using threads, but they have a few key differences.

    The main difference is that Tasks in .NET 4.0 dont actually correlate to a new thread, they are executed on the new thread pool that is being shipped in .NET

    4.0. So, creating a new task is similar to what we did in .NET 2.0 when we said:

    Okay, so if all we are doing is just plopping a new task on the thread pool, then why do we need this new Task namespace? Well, Im glad you asked! In

    previous versions of .NET, when we put an item on the thread pool, we had a very hard time getting any information back about what exactly was going on with

    the piece of work that we had just queued. For example, in the code above, what would we have had to do in order to wait on that piece of work to finish? The

    thread pool doesnt give us any built-in way to do this, it is just fire and forget.

    In order to wait, we could have done something like this:

    But that is just a tad bit ugly. And what if we wanted to specify some piece of code that would execute directly after that queued work, and then would use the

    result? Or what if we wanted to fire off a few pieces of work and then wait for all of them to finish before continuing? Or what if we only wanted to wait for just

    one of them to finish? What if we wanted to return some value from the piece of work, but block if the result was requested before it was available? What about

    all of those things? A bit daunting, right? Well, all of this functionality is exactly why Tasks in .NET 4.0 exist!

    Creating Tasks

    Lets look at how we could create one of these tasks:

    Hey, that is pretty simple, and it doesnt look too far removed from throwing items on the thread pool! In fact, when we execute this line, we really are just

    dropping a task on the thread pool because we arent getting a reference to the task so that we can use its extra functionality! To do this, we could simply assign

    1 ThreadPool.QueueUserWorkItem(_ => DoSomeWork());

    123456

    var mre = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(_ => {

    DoSomeWork();mre.Set();

    });mre.WaitOne();

    1 Task.Factory.StartNew(() => DoSomeWork());

    ?

    ?

    ?

    http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#
  • 7/27/2019 .NET 4.0 and System.threading

    3/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 3/14

    the result to a variable:

    This way we now have a reference to the task.

    So, how is this different from creating a thread again? Well, one of the first advantages of using Tasks over Threads is that it becomes easier to guarantee that

    you are going to maximize the performance of your application on any given system. For example, if I am going to fire off multiple threads that are all going to be

    doing heavy CPU bound work, then on a single core machine we are likely to cause the work to take significantly longer. You see, threading has overhead, and

    if you are trying to execute more CPU bound threads on a machine than you have available cores for them to run, then you can possibly run into problems. Each

    time that the CPU has to switch from thread to thread causes a bit of overhead, and if you have many threads running at once, then this switching can happen

    quite often causing the work to take longer than if it had just been executed synchronously. This diagram might help spell that out for you a bit better:

    As you can see, if we arent switching between pieces of work, then we dont have the context switches between threads. So, the total cumulative time to

    process in that manner is much longer, even though the same amount of work was done. If these were being processed by two different cores, then we could

    simply execute them on two cores, and the two sets of work would get executed simultaneously, providing the highest possible efficiency.

    Because of this fact, Tasks (or more accurately the thread pool) automatically try to optimize for the number of cores available on your box. However, this is not

    always the case, sometimes you will fire off threads that will perform actions which require a large amount of waiting. Something like calling a web service, firing

    off a database query, or simply waiting for some other long running process. With this sort of workload we probably want to execute more than one thread per

    core. Think about that, if we had 10 different urls that we wanted to download a web page from, we probably dont want to just fire off two at a time on a dual

    core machine. Since downloading a file from the web isnt very CPU intensive, we probably want to go ahead and fire all of them off at once so that we gain as

    much as we can from parallel execution. If this was the case, the above task would be executed like this:

    1 var task = Task.Factory.StartNew(() => DoSomeWork());

    1 Task.Factory.StartNew(() => DoSomeWork(), TaskCreationOptions.LongRunning);

    ?

    ?

    http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#
  • 7/27/2019 .NET 4.0 and System.threading

    4/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 4/14

    Again, very easy, all we have to do is tell the task factory that this is a long running task, and it will use a different heuristic to determine how many threads to

    execute the tasks on.

    Waiting On Tasks

    Earlier I said that one of the nice features of Tasks was the ability to wait on them easily. In order to do this it is merely a one liner:

    The task will be queued up on the thread pool, and the call to "Wait" will block until its execution is complete. What if we had multiple tasks and we need to

    wait on all of them. Again, it is a simple one liner:

    That sure was hard. And what if we had multiple tasks, and we just wanted to wait for one of them to complete, but we didnt care which one yup, youguessed it, another one-liner:

    Again, this task is made very easy by the Task APIs. Earlier I also mentioned something about being able to have a task produce a value, and then block until

    this value is produced. Well, first we have to look at how we create a task which returns a value. To test this functionality, lets go ahead and create a task that

    looks like this:

    This task is just going to wait a few seconds then return a dummy value. Because the lambda is now returning a value, it is going to use the overload of

    12 var task = Task.Factory.StartNew(() => DoSomeWork());task.Wait();

    1234

    var task1 = Task.Factory.StartNew(() => DoSomeWork());var task2 = Task.Factory.StartNew(() => DoSomeWork());var task3 = Task.Factory.StartNew(() => DoSomeWork());Task.WaitAll(task1, task2, task3);

    1234

    var task1 = Task.Factory.StartNew(() => DoSomeWork());var task2 = Task.Factory.StartNew(() => DoSomeWork());var task3 = Task.Factory.StartNew(() => DoSomeWork());Task.WaitAny(task1, task2, task3);

    12345

    var task = Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value";});

    ?

    ?

    ?

    ?

    http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#
  • 7/27/2019 .NET 4.0 and System.threading

    5/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 5/14

    "StartNew" that takes a Func instead of an Action. So, the task that is produced is now a Task instead of just a Task. The generic parameter T

    specifies what the type of the result is going to be. The Task type has a property on it called "Result" which will block when we access it. So if we executed

    the following code, then it would run without incident:

    This quite useful! The task is going to execute on a separate thread, and will take 3 seconds. When we call Console.WriteLine though, we wont get an

    exception because the value is not there, we will simply block and wait until the value is available before continuing on. This can be exceedingly useful when used

    in conjunction with the long running tasks, since it easily allows us to execute a large number of long running operations and then just ask for their results, knowing

    that they will simply block until the operations are complete.

    Tasks And Continuations

    Another really cool feature of Tasks in .NET 4.0 is the ability to create continuations. By this I mean that we can execute a task or a number of tasks and then

    have a task which will execute after their completion, and even be able to use the result of their execution! It provides a very easy mechanism of coordinating

    complex thread behaviors.

    Lets say in the example above, instead of calling "Result" and waiting for it to finish, I could have used a continuation in order to write the value to the console on

    a separate thread when the task was done executing. In this case, I would not have had any blocking at all, the application would have continued executing, but

    when the 3 seconds was up, the continuation would be executed and the value would have been written out to the console. The code would look like this:

    Very powerful. In the example above we are creating the continuation inline, but we could add it on a second line as well:

    1234

    56

    var task = Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value";

    });Console.WriteLine(task.Result);

    12345

    Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value";}).ContinueWith(task => Console.WriteLine(task.Result));

    12

    var task = Task.Factory.StartNew(() =>{

    ?

    ?

    ?

    http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#
  • 7/27/2019 .NET 4.0 and System.threading

    6/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 6/14

    We can also do more than just a single continuation, we can chain on any number of continuations:

    Continuations provide us with much more rich behavior such as specifying that they should only be executed when an error occurs, when cancellation occurs, we

    can say that the continuation is long running, we can specify that it is executed on the same thread as its parent, etc There is a lot there, and I encourage you to

    explore all of the overloads on the "ContinueWith" method.

    Not only can we perform a continuation on a single task, but we can use static methods on the Task class to allow us to perform continuations on a set of tasks:

    3456

    Thread.Sleep(3000); return"dummy value";});task.ContinueWith(t => Console.WriteLine(t.Result));

    1

    234567

    Task.Factory.StartNew(() =>

    { Thread.Sleep(3000); return"dummy value";}).ContinueWith(t => Console.WriteLine(t.Result)).ContinueWith(t => Console.WriteLine("We are done!"));

    123456789

    1011121314151617

    var task1 = Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value 1";});var task2 = Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value 2";});var task3 = Task.Factory.StartNew(() =>{

    Thread.Sleep(3000); return"dummy value 3";});

    ?

    ?

    http://www.codethinked.com/net-40-and-systemthreadingtasks#http://www.codethinked.com/net-40-and-systemthreadingtasks#
  • 7/27/2019 .NET 4.0 and System.threading

    7/7

    08/08/13 .NET 4.0 and System.Threading.Tasks | CodeThinked

    www.codethinked.com/net-40-and-systemthreadingtasks 7/14

    Tweet 16

    This way, all tasks will finish, and then we can use each of their results. ContinueWhenAll doesnt block at all, so you might need to add a call to "Wait()" at the

    end if you are executing inside of a console application.

    Summary

    This has only been a very light introduction to all of the features that the System.Threading.Tasks namespace gives you in .NET 4.0, but I hope that it has piqued

    your interest enough that you will want to go spend some time exploring it! Enjoy!

    Be Sociable, Share!

    This entry was posted on Monday, January 25th, 2010 at 4:05 pm and is filed underSoftware Development. You can follow any comments to this entry through the RSS 2.0 feed. You

    can leave a comment, ortrackbackfrom your own site.

    22 comments

    1. Matt Hidinger

    January 25, 2010 at 6:03 pm

    This indeed looks like a great set of APIs. Interesting that Ive only just head about it now. Did you happen to have any other good resources while

    researching this post, or mainly digging around with IntelliSense?

    1819202122232425

    Task.Factory.ContinueWhenAll(new[] { task1, task2, task3 }, tasks =>{ foreach (Task task in tasks)

    {Console.WriteLine(task.Result);

    }});

    ShareShare

    http://www.codethinked.com/net-40-and-systemthreadingtasks/comment-page-1#comment-3050http://www.matthidinger.com/http://www.codethinked.com/net-40-and-systemthreadingtasks/trackbackhttp://www.codethinked.com/net-40-and-systemthreadingtasks#respondhttp://www.codethinked.com/net-40-and-systemthreadingtasks/feedhttp://www.codethinked.com/category/software-developmenthttps://twitter.com/sharehttp://www.blinklist.com/index.php?Action=Blink/addblink.php&Url=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&Title=.NET%204.0%20and%20System.Threading.Taskshttp://www.linkedin.com/shareArticle?mini=true&url=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&title=.NET%204.0%20and%20System.Threading.Tasks&source=CodeThinked+by+Justin+Etheredge&summary=In%20the%20soon-to-be-released%20.NET%204.0%20framework%20and%20Visual%20Studio%202010%20we%20are%20going%20to%20get%20a%20plethora%20of%20new%20tools%20to%20help%20us%20write%20better%20multi-threaded%20applications.%20One%20of%20these%20tools%20is%20a%20new%20namespace%20within%20the%20System.Threading%20namespace%20which%20ishttp://www.google.com/reader/link?url=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&title=.NET%204.0%20and%20System.Threading.Tasks&srcURL=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&srcTitle=CodeThinked+by+Justin+Etheredgehttp://delicious.com/post?url=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&title=.NET%204.0%20and%20System.Threading.Tasks&notes=In%20the%20soon-to-be-released%20.NET%204.0%20framework%20and%20Visual%20Studio%202010%20we%20are%20going%20to%20get%20a%20plethora%20of%20new%20tools%20to%20help%20us%20write%20better%20multi-threaded%20applications.%20One%20of%20these%20tools%20is%20a%20new%20namespace%20within%20the%20System.Threading%20namespace%20which%20ishttp://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&title=.NET%204.0%20and%20System.Threading.Taskshttps://mail.google.com/mail/?view=cm&fs=1&to&su=.NET%204.0%20and%20System.Threading.Tasks&body=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&ui=2&tf=1&shva=1http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks&t=.NET%204.0%20and%20System.Threading.Taskshttp://twitter.com/intent/tweet?text=.NET%204.0%20and%20System.Threading.Tasks%20-%20http%3A%2F%2Fwww.codethinked.com%2Fnet-40-and-systemthreadingtasks%20