This one’s just a bit of “fun” for a Friday afternoon ( depending on how you define “fun”
).
I was writing some asynchronous code yesterday in JavaScript and I then had cause to duplicate it in .NET using the await support of the Async CTP which I’ve tried to write about before ( generally and combined with Rx ).
This led into a debate with a colleague where we started passing bits of code backwards and forwards and got down to some simple cases and I thought I’d share here in the form of a “quiz” 
This isn’t meant to be even slightly comprehensive, it’s just that I found that we tended to start with small, simple examples and then build them up a little and so I thought I’d re-use some of those pieces of code here.
So…roll up and see how many points you can score with a few quiz questions on the async CTP.
Before we get going…
Before we start – I’m using TaskEx.Delay here and you might have the async CTP but you might not have seen TaskEx.Delay so I’ll say from the docs that it;
“Starts a Task that will complete after the specified due time.”
the bolding is mine because I think it’s vital to know that it starts a task rather than just creates one.
Note that there are no “trick” questions with the exception of question 2 which is just nasty.
and we’re not quite ready yet…
We create some tasks here which will need assigning to threads in order to run them – that introduces an element of non-determinism (e.g. the threadpool can pretty much do whatever it likes) so where I’m saying “how long does this piece of code take to run” I’m really saying “how long does it take to run given that the scheduler does more or less what you’d expect it to”).
This introduces an element of non-determinism into the quiz 
Now…on with the quiz;
Question 1 ( 5 points )
(Approximately) how many seconds will this program print to the console?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TaskEx.Delay(TimeSpan.FromSeconds(3));
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
}
Question 2 ( 20 points )
Again, approximately how many seconds will this program print to the console?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static async void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
await TaskEx.Delay(TimeSpan.FromSeconds(3));
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
}
Question 3 ( 5 points )
Ok, I apologise for the last question, that was really nasty. Let’s get back onto more reasonable ground here with a better class of question. What about this one?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
TaskEx.Delay(TimeSpan.FromSeconds(3)).Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
}
Question 4 ( 5 points )
And, to rebuild more trust in the pillock setting the questions
here’s a similar situation, what will this one print?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
await TaskEx.Delay(TimeSpan.FromSeconds(3));
}
}
Question 5 ( 10 points )
Just to check that you’re still with me, looking at the code example below and the assertions within it, which of the assertions will fail and throw a big, nasty dialog to the screen?
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static int threadId;
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
threadId = Thread.CurrentThread.ManagedThreadId;
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
Debug.Assert(Thread.CurrentThread.ManagedThreadId == threadId);
await TaskEx.Delay(TimeSpan.FromSeconds(3));
Debug.Assert(Thread.CurrentThread.ManagedThreadId == threadId);
}
}
Possible Answers ( these would be a,b,c if I could get Live Writer to do it
)
- The one on line 24.
- The one one line 28.
- Both of the ones on line 24 and on line 28.
- None of them.
- I’m still not talking to you after question number 2. That was a really nasty thing to put so early in the quiz.
Question 6 ( 5 points )
Back from the leisures of multiple choice answers to working out timings – how long will this one print to the console?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
await TaskEx.Delay(TimeSpan.FromSeconds(3));
await TaskEx.Delay(TimeSpan.FromSeconds(2));
}
}
Question 7 ( 10 points )
And we’re still stuck in the world of timings, what about this one?
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
for (int i = 0; i < 3; i++)
{
await TaskEx.Delay(TimeSpan.FromSeconds(3));
await TaskEx.Delay(TimeSpan.FromSeconds(2));
}
}
}
Question 8 ( 10 points )
Starting to act a little differently;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
await TaskEx.WhenAll(
TaskEx.Delay(TimeSpan.FromSeconds(3)),
TaskEx.Delay(TimeSpan.FromSeconds(2)));
}
}
Question 9 ( 5 points )
Very similar;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
await TaskEx.WhenAny(
TaskEx.Delay(TimeSpan.FromSeconds(3)),
TaskEx.Delay(TimeSpan.FromSeconds(2)));
}
}
Question 10 ( 10 points )
Back to loops;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
for (int i = 0; i < 3; i++)
{
await TaskEx.WhenAny(
TaskEx.Delay(TimeSpan.FromSeconds(3)),
TaskEx.Delay(TimeSpan.FromSeconds(2)));
}
}
}
Question 11 ( 15 points )
We’re still with loops but we’re being a little bit more sneaky
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Foo().Wait();
sw.Stop();
Console.WriteLine("The program took {0} seconds", sw.Elapsed.Seconds);
}
static async Task Foo()
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
tasks.Add(TaskEx.Delay(TimeSpan.FromSeconds(3)));
tasks.Add(TaskEx.Delay(TimeSpan.FromSeconds(2)));
}
await TaskEx.WhenAll(tasks);
}
}
and 11 is where I ran out of steam without wandering away from TaskEx.Delay and into other territory.
Answers ( I think )
I think these are the answers (with a little bit of explanation);
- Answer is 0 seconds. There’s no code that waits for anything so it’s just going to start that task and then stop the stopwatch straight away. 5 points.
- Answer is “this example doesn’t print anything”. Try it. This is to do with trying to be async inside of main and there’s a thread up at the forums that talks about it. Sorry. Trick question. Nasty. 20 points and if you knew this already then you’ve been there before.
- Answer is 3 seconds. We create a Task that delays for 3 seconds and we wait for it. 5 points.
- Answer is 3 seconds. This is really the same as question 3 with some more thrown in. 5 points.
- Answer is option 2 – the assertion on line 28. When the await completes, some thread has to call the “callback” to continue the work here and it can’t be our main thread because it’s blocked in a call to Wait() so it has to be another thread. Note – in other scenarios where there’s a synchronization context in play, this might be different. 5 points.
- Answer is 5 seconds – we first wait for 3 seconds and then for 2 seconds so that’s 5. 5 points.
- Answer is 15 seconds – we loop around 3 times waiting for 3 and then 2 seconds so that’s 15. 10 points.
- Answer is 3 seconds. We have 2 waits to wait for and the longest is 3. 5 points.
- Answer is 2 seconds. We wait for the first wait and the shorted is 2. 5 points.
- Answer is 6 seconds. We loop 3 times over the previous scenario doing an await each time so that means 6 seconds. 10 points.
- Answer is 3 seconds. We make 6 separate tasks with the longest taking 3 seconds and they all (probably!!!!) run concurrently and then we wait for all of them. 15 points.
Scores
I think there are 90 points up for grabs there so if you managed to genuinely get 50+ I think you’re doing pretty well and have perhaps seen some of this stuff before or played with it.
If you managed 90 then you can feel very proud of yourself.
If you got 0 then you’ve perhaps got some reading to do or perhaps were searching the web for “a sink CTP” and were looking for “Copper Sinks – CTP Systems” – in that case, I can only apologise 