Archives for : January2014

The Task Parallel Library Sampler – Part 14: Wrap-up / Future posts

This has been a fun journey and hopefully you’ve learned a bit about MVVM and the TPL. I do have plans for future posts in this series that will center around the TPL.Dataflow namespace. It’s an area of the TPL I don’t seem written about a lot and I think there are probably a few posts that would benefit you.

My next series of posts, however, is on the SOLID principles of good object-oriented programming and design. Often when it comes to concepts like design patterns and MVVM we can’t see the forest from the trees and we get lost in the concepts. The awesome thing about SOLID is that it is so straight-forward that all of us should have a thorough understanding of it.

After SOLID, I have a series planned on design patterns. I won’t cover all the design patterns but will hit on quite a few of them. I also have a post planned on the patterns you don’t really care about if you apply fundamental .net development concepts and practices as the patterns are incorporated into those practices. This will relate to patterns like lazy initialization, object/thread pool, factory method and dependency injection, observer, locking and scheduling, all of which I have hit on in some form or another in assorted posts here while not necessarily calling them out as such patterns.

I always welcome your feedback and allow anonymous comments so feel free to comment on anything. Spam and off-topic/inappropriate comments are and always will be removed.

Full series of posts:
Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework
Part Three: Base Classes
Part 4: Sampler View, View Model and Model
Part 5: Running and working with the TPL samples
Part 6: Parallel.For Sample
Part 7: Using Parallel.For effectively
Part 8: Adding a New Sample, Matrices Multiplication
Part 9: Basic Exception handling with the AggregateException
Part 10: Loop control of the Parallel.For and .ForEach
Part 11: Cancelling Threads with the CancellationTokenSource – The MVVM
Part 12: Cancelling Threads with the CancellationTokenSource – The Code
Part 13: Async/Await

Thanks,
Brian

The Task Parallel Library Sampler – Part 13: Async/Await

Previous Post in this series:
Part 12: Cancelling Threads with the CancellationTokenSource – The Code

This sample derives from a Microsoft example and an updated solution is available here.

AsyncAwaitSample model:

public class AsyncAwaitSample : Sample
{
	public override string SampleName
	{
		get { return "Async/Await Sample"; }
	}

	public override bool ImageRequired
	{
		get { return false; }
	}

	public async override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
	{
		Stopwatch s = new Stopwatch();
		s.Start();

		UpdateLog("Step 1 (Run 1): Starting an await call to an asyncronous method.");
		int result = await AccessTheWebAsync("Run 1", UpdateLog);
		UpdateLog("Step 6 (Run 1): Done await call to an asyncronous method.");

		//this works and will even run asynchronously but won't wait on any result.
		//more then likely we will be long gone from this method before the method below is done
		UpdateLog(Environment.NewLine + "Step 1 (Run 2): Starting an async call without await and no result.");
		AccessTheWebAsync("Run 2", UpdateLog);
		UpdateLog("Step 6 (Run 2): Done with the async call without await and no result");

		s.Stop();
		RunTime = s.Elapsed;
	}

	// Three things to note in the signature: 
	//  - The method has an async modifier.  
	//  - The return type is Task or Task<T>. (See "Return Types" section.)
	//    Here, it is Task<int> because the return statement returns an integer. 
	//  - The method name ends in "Async."
	async Task<int> AccessTheWebAsync(string runDesignation, Action<string> UpdateLog)
	{
		// You need to add a reference to System.Net.Http to declare client.
		HttpClient client = new HttpClient();

		// GetStringAsync returns a Task<string>. That means that when you await the 
		// task you'll get a string (urlContents).
		// This also allows you set a lot of properties on the task rather then just running
		// it if you need to.
		Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
		UpdateLog("Step 2 (" + runDesignation+ "): Sleeping for ten seconds.");
		await Task.Delay(10000);
		UpdateLog("Step 3 (" + runDesignation+ "): Woke up.");
		UpdateLog("Step 4 (" + runDesignation+ "): Getting the web page.");
		// The await operator suspends AccessTheWebAsync. 
		//  - AccessTheWebAsync can't continue until getStringTask is complete. 
		//  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
		//  - Control resumes here when getStringTask is complete.  
		//  - The await operator then retrieves the string result from getStringTask. 
		// This could also have been done as 
		// string urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
		string urlContents = await getStringTask;
		UpdateLog("Step 5 (" + runDesignation+ "): Got the web page.");
		// The return statement specifies an integer result. 
		// Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
		return urlContents.Length;
	}
}

There are two runs here, one shown using the keyword “await” with an asyncronous method and another run just running an asyncronous method without using “await”. It is very important to understand the conventions when using async. That is the name of the method should contain “async” in it. As an example, the HttpClient.GetStringAsync() makes it obvious that it is an async method. As shown in the comments, when calling an async method with await, the current thread calls the method and then waits for the method to return before continuing. If an asyncronous method is called without using await, a seperate thread is spun off and execution continues on. This can be very dangerous if there are results you’re waiting for from an asyncrounous method.

Run results:

Starting Async/Await Sample
Step 1 (Run 1): Starting an await call to an asyncronous method.
Step 2 (Run 1): Sleeping for ten seconds.
Completed Async/Await Sample
Async/Await Sample ran in 00:00:10.0173992

Step 3 (Run 1): Woke up.
Step 4 (Run 1): Getting the web page.
Step 5 (Run 1): Got the web page.
Step 6 (Run 1): Done await call to an asyncronous method.

Step 1 (Run 2): Starting an async call without await and no result.
Step 2 (Run 2): Sleeping for ten seconds.
Step 6 (Run 2): Done with the async call without await and no result
Step 3 (Run 2): Woke up.
Step 4 (Run 2): Getting the web page.
Step 5 (Run 2): Got the web page.

Looking at Run 1 you can see that AsyncAwaitSample.Run() is started, the first run is started and then we get the message that the sample is done. But why? Because we’re calling the run method, which is asynchronous, without await, down in the Sampler model. As such, the calling code calls the method, a thread gets spun up, and then execution continues in the original calling code. It never waits, just continues. So why define the method as “async”? Because the only way to use await with an asynchronous method is if the method itself is async. If you look at Run 2, it is even more obvious what happens when you call an async method without using await. Run 1, which uses await, runs the steps sequentially (other then the messages from Sampler model). Run 2 clearly does the steps out of order.

Another important point, the Run method is defined by a base class, as such the Sampler model is just calling run on all it’s samples. But what is interesting is that we are able to make Run into an async method, which we have to do to use await, and we are given no warning from Sampler that we may be calling an async method without using await. Now, in AsyncAwaitSample we are given a warning that for Run 2 we are calling an async method without await. But there it is more obvious that we are doing so.

In the first post in this series I said there would be 15 posts but it looks like there will be only 14. The next post will be a wrap-up/final to this series.

Thanks,
Brian

Previous Post in this series:
Part 11: Cancelling Threads with the CancellationTokenSource – The MVVM

So now that we’ve covered the MVVM, which you saw was pretty trivial to implement, let’s cover the actual sample.

CancellationSample.Run

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	Stopwatch s = new Stopwatch();
	s.Start();

	IsRunning = true;

	CancellationTokenSource = new CancellationTokenSource();
	CancellationTokenSource.Token.Register(() => { IsRunning = false; });

	var options = new ParallelOptions { CancellationToken = CancellationTokenSource.Token };
	try
	{
		Parallel.ForEach(WhileTrue(), options, i =>
		{
			while (!options.CancellationToken.IsCancellationRequested)
			{
				UpdateLog("Sleeping in Cancellation Sample at " + i);
				Thread.Sleep(ran.Next(1000));
			}
		});
	}
	catch (OperationCanceledException)
	{
		UpdateLog("Operation has been cancelled."); ;
	}

	s.Stop();
	RunTime = s.Elapsed;
}

public static IEnumerable<int> WhileTrue()
{
	for (int i = 0; ; i++)
		yield return i;
}

We start by instantiating the CancellationTokenSource that holds our token. We have to do this for each run or else the token is already cancelled and the threads in the Parallel.ForEach won’t spawn.

Line 9 is pretty interesting. We’re registering a call-back to fire when the token gets cancelled. Here we set “IsRunning” to false but you can put any delegate here. This way when whatever code external to us cancels the token then we can handle the IsRunning.

Next we instantiate a ParallelOptions, setting the CancellationToken to the Token of the CancellationTokenSource.

The most important thing with all this is to note that cancelling the CancellationTokenSource doesn’t stop any threads, it just prevents more threads from being spawned. Because of this we have to check in our while loop if the CancellationToken has been cancelled and if it has been then stop. When canceling the CancellationTokenSource this will cause an OperationCanceledException to be thrown. This way you can handle if there is any clean-up that needs to happen if your Parallel.For and .ForEach may not have completed. In our case I’m using a “WhileTrue” that just goes on infinitely.

Up next I’ll go into async/await.

Thanks,
Brian

Previous Post in this series:
Part 10: Loop control of the Parallel.For and .ForEach

Next up we’ll work on cancelling threads with the CancellationTokenSource. This is really a two parter where the first part will deal with the changes I had to make to integrate a new view and the second part covering the sample model. There is an update set of code available.

Since we’re going to want to cancel a thread once we’ve started it we’ll need a mechanism for the user to do so. Working from the model to the view model to the view we’ll see how I do this.

CancellationSample

public class CancellationSample : Sample
{
	public override string SampleName
	{
		get { return "Cancellation Sample"; }
	}

	public override bool ImageRequired
	{
		get { return false; }
	}

	bool isRunning = false;
	public bool IsRunning
	{
		get { return this.isRunning; }
		set
		{
			if (this.isRunning != value)
			{
				this.isRunning = value;
				this.RaisePropertyChanged("IsRunning");
			}
		}
	}
			
	public CancellationTokenSource CancellationTokenSource { get; set; }

	private static Random ran = new Random();

	public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
	{
		Stopwatch s = new Stopwatch();
		s.Start();

		IsRunning = true;

		CancellationTokenSource = new CancellationTokenSource();
		CancellationTokenSource.Token.Register(() => { IsRunning = false; });

		var options = new ParallelOptions { CancellationToken = CancellationTokenSource.Token };
		try
		{
			Parallel.ForEach(WhileTrue(), options, i =>
			{
				while (!options.CancellationToken.IsCancellationRequested)
				{
					UpdateLog("Sleeping in Cancellation Sample at " + i);
					Thread.Sleep(ran.Next(1000));
				}
			});
		}
		catch (OperationCanceledException)
		{
			UpdateLog("Operation has been cancelled."); ;
		}

		s.Stop();
		RunTime = s.Elapsed;
	}

	public static IEnumerable<int> WhileTrue()
	{
		for (int i = 0; ; i++)
			yield return i;
	}
}

Above you can see the CancellationTokenSource we’re using but as I said I’ll go into further detail on the next post. For the most part this is virtually identical to the other samples provided. There are two new properties exclusive to this class, the IsRunning property that defines when the run method is started and ended and the CancellationTokenSource itself.

CancellationSampleViewModel

public class CancellationSampleViewModel : SampleViewModel
{
	public CancellationSampleViewModel(CancellationSample Sample) : base(Sample) { }
	
	public void CancelRun()
	{
		((CancellationSample)Sample).CancellationTokenSource.Cancel();
	}
}

The view model for the CancellationSample couldn’t be much easier. As you know, view models act as a go-between from the model and the view. In this case we expose a method to cancel a run where we just call the cancel method on the CancellationTokenSource.

CancellationSampleView.xaml

<UserControl x:Class="TPLSamples.Views.CancellationSampleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <CheckBox Grid.Row="0" IsChecked="{Binding Sample.IsEnabled, Mode=TwoWay}" Content="{Binding Sample.SampleName}" ToolTip="{Binding Sample.SampleName}" />
        <Button Grid.Row="1" Margin="5" Content="Cancel Run" Visibility="{Binding Path=Sample.IsRunning, Converter={StaticResource BoolToVis}}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding}" MethodName="CancelRun" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

This view is similiar to the generic SampleView.xaml with the addition of the button for cancelling the run. There are a few points of note. The first is the Interaction.Triggers to fire on the button click event. We bind to the CancelRun method of the view model that was previously mentioned. This is just like how the Submit/Reset buttons are set up. Next is the BooleanToVisibilityConverter in the resources of the control which is a standard class available in “System.Windows.Controls”. We use that to set the visibility of the button based on when the sample is running. As with the other view we bind directly to the model property, in this case “IsRunning”. As mentioned in a previous post this isn’t the truest of MVVM as these properties should be exposed in the ViewModel. This is problematic as it introduces a dependency directly between your view and model. In this instance, however, the code is a lot cleaner to understand when we just bind directly to the model and I feel justified in using this way.

As with nearly all MVVM implementations the code-behind is just the boiler-plate code created for us.

Finally I need to discuss what I had to change to the code to support the new model. In the SamplerViewModel I added it as I’ve added other models and view models. What had to really change is the ItemsControl.

SamplerView.xaml ItemsControl

<ItemsControl Grid.Row="1" IsTabStop="False" ItemsSource="{Binding Samples}">
	<ItemsControl.ItemsPanel>
		<ItemsPanelTemplate>
			<WrapPanel Orientation="Horizontal" IsItemsHost="True" Utility:MarginUtilities.Margin="5" />
		</ItemsPanelTemplate>
	</ItemsControl.ItemsPanel>
	<ItemsControl.Resources>
		<DataTemplate DataType="{x:Type ViewModels:CancellationSampleViewModel}">
			<Views:CancellationSampleView DataContext="{Binding}" />
		</DataTemplate>
		<DataTemplate DataType="{x:Type ViewModels:SampleViewModel}">
			<Views:SampleView DataContext="{Binding}" />
		</DataTemplate>
	</ItemsControl.Resources>
	<!--<ItemsControl.ItemTemplate>
		<DataTemplate>
			<Views:SampleView DataContext="{Binding}" />
		</DataTemplate>
	</ItemsControl.ItemTemplate>-->
</ItemsControl>

I left commented out the ItemTemplate for the SampleView. Since we were originally only using just the base SampleView this made since. Now that we’ve expanded the Views possible we need to provide a mapping of the view models to the correct view as we’re going to do this in the resources. You can see all we’re doing is defining for each view model a view. The order is not important and the binding will take care of assigning the most restrictive type possible. So even if we flip the two data templates the final binding works correctly.

That’s all for now. As I mentioned in next week’s post I’ll go into detail on the sample and what it’s doing.

Thanks,
Brian