| |
|
Action Delegate and Task Parallelism in C#
|
| |
|
|
| |
| 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. |
| |
|
|
| |
|
|
| |
|
|
| |
| |
| Posts: 113 |
| Comments:
86 |
| Fundamentals:
16 |
| |
 |
| |
| |
|
| |
 |
| |
 |
| |
 |
| |
|
| 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) |
| |
| |
|
| |
|
|
| |
| |
|
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.
|
| |
|
| | | |