The Best C# Programmer In The World - Ben Perkins Member Login  | Newsletter | RSS Feeds


 
 
 
TheBestCSharpProgrammerInTheWorld.com 
 
The Best C# Programmer In The World - Ben Perkins
Action Delegate and Task Parallelism in C#  
 
Action Delegate and Task Parallelism in C#
 
Please rate:
 
I wrote a WPF program recently that contained 2 treeviews which were dynamiclly created, in part, by data located on a database. Initially, I had the creation of the treeviews in my Windows_Loaded method, executing the build one after the other. The performance was ok, it took about 1.8 to 2 seconds for the window to render and be ready for user input. I reviewed the code and thought to myself that I did not need to wait for one treeview to be built before I start, or complete, the other treeview. I could hear the code begging me to make these 2 lines run in parallel. So I did and now it takes less than .5 of a second for the window to render. Seeing it open now is like "instant on".
 
At first when I started coding it, I broke the UI thread rule. This rule states that UI elements can only be manipulated by the thread it was created on. My first reaction to this error was to try and strip apart the methods. Meaning that I looked at the methods and thought about taking activities out which manipulated the UI, putting them into another method that I can call from the UI Thread. Luckily, it worked out good and I got a heavy method that could be called from a parallel thread and didn't try to modify anything on the UI.
 
My original code was this:
 
                        
                        TreeView1.ItemsSource = TreeViewModel.SetTree(true, true);
                        TreeView2.ItemsSource = TreeViewModel.SetTree(true, false);
                        
 
Like I mentioned already, doing the above in procedurally took about 2 seconds.
 
I modified my code to use an Action delegate and the Task class found in the Task Parallel Library. By doing this the 2 second activity was reduced to < .5 of a second.
 
                        
                        TaskScheduler uiThread = 
                            TaskScheduler.FromCurrentSynchronizationContext();
                            
                        Action BackgroundThread = new Action(() =>
                        {
                          treeViewClass1 = TreeViewModel.SetTree(true, true);
                          treeViewClass2 = TreeViewModel.SetTree(true, false);
                        });
                        
                        Action UiThread = new Action(() =>
                        {
                          TreeView1.ItemsSource = treeViewClass1;
                          TreeView2.ItemsSource = treeViewClass2;
                        });

                        var Task1 = Task.Factory.StartNew(() => BackgroundThread());
                        var Task2 = Task1.ContinueWith(t => UiThread(), uiThread);
                        
 
I first got the current UI thread context, so that I could use it later on in my code. I would need this to make sure when I execute a method that manipulates a UI element, that I use the correct thread.
 
Then I create my 2 Action delegates. The first one can run on a background thread and the second one I need to run on the UI thread becuase this is where I load the ItemsSource of the treeview control.
 
Lastly, I create my first Task, where I use a Lambda Expression to define the delegate and finally use the instance of the first task to call the ContinueWIth method. The ContinueWith method accepts a parameter for the thread to use, we pass it the UI thread we created at the start.
 
I was actually an amazing experience to see the performance improve so much. I had to run it a few times and stop it in Debug mode becuase it just seemed to run too fast. I thought it couldn't possibly be doing everything it was before so fast. I was wrong, it's fast, it rocks and I will implement this often from now on.
 
NOTE: When you begin the design of a project keep in mind what you have learned here. Like object-oriented design, you need to think about designing your methods in a way that allows for parallelism. I am sure there are some methods that simply can not be multi-threaded becuase they do non-UI work and UI work within the same unit. If you want you system to be object-oriented, start with a good object-oriented design. If you want to be able to run your method in parallel, design them with this capability.
 
 
Feedback / Question
 
Your Name:Your Email:
 
Subject:
 
Feedback/Question:
 
 
 
I had to remove the capability to leave feedback due to this. Will be back soon.
 
 
Comment posted: 1/23/2011 9:41:55 AM by Ben Perkins
 
It still takes the program about 2 seconds to be ready for the user to begin working. However, the GUI is immediately available since the connection to the database and business logic are running on a different thread than the thread which renders the GUI.
 
page.Translate()
 
 
blog.Stats()
 
  Posts: 113
  Comments: 86
  Fundamentals: 16
 
my.Book()

 
me.About()
 
 
 
 
 
blog.Archive()
 
2012 May  (4)
2012 April  (5)
2012 March  (4)
2012 February  (4)
2012 January  (5)
2011 December (2)
2011 November (6)
2011 October (7)
2011 September (7)
2011 August (9)
2011 July (9)
2011 June (8)
2011 May (9)
2011 April (7)
2011 March (9)
2011 February (8)
2011 January (8)
2010 December (7)
2010 November (8)
2010 October (4)
 
site.Visits()
 
free counters
 
tag.Cloud()
 
code.Disclaimer()
 
The sample code on this website is provided to illustrate a concept and should not be used in applications or Web sites without proper professional consultation, as it may not illustrate the safest coding practices. I assume no liability for incidental or consequential damages should the sample code be used for purposes other than as intended.
 
   


The Best C# Programmer In The World - Ben Perkins, © 2010, All Rights ReservedContact Ben