When would I use Task.Yield()? - c#

I'm using async/await and Task a lot but have never been using Task.Yield() and to be honest even with all the explanations I do not understand why I would need this method.
Can somebody give a good example where Yield() is required?

When you use async/await, there is no guarantee that the method you call when you do await FooAsync() will actually run asynchronously. The internal implementation is free to return using a completely synchronous path.
If you're making an API where it's critical that you don't block and you run some code asynchronously, and there's a chance that the called method will run synchronously (effectively blocking), using await Task.Yield() will force your method to be asynchronous, and return control at that point. The rest of the code will execute at a later time (at which point, it still may run synchronously) on the current context.
This can also be useful if you make an asynchronous method that requires some "long running" initialization, ie:
private async void button_Click(object sender, EventArgs e)
{
await Task.Yield(); // Make us async right away
var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later
await UseDataAsync(data);
}
Without the Task.Yield() call, the method will execute synchronously all the way up to the first call to await.

Internally, await Task.Yield() simply queues the continuation on either the current synchronization context or on a random pool thread, if SynchronizationContext.Current is null.
It is efficiently implemented as custom awaiter. A less efficient code producing the identical effect might be as simple as this:
var tcs = new TaskCompletionSource<bool>();
var sc = SynchronizationContext.Current;
if (sc != null)
sc.Post(_ => tcs.SetResult(true), null);
else
ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true));
await tcs.Task;
Task.Yield() can be used as a short-cut for some weird execution flow alterations. For example:
async Task DoDialogAsync()
{
var dialog = new Form();
Func<Task> showAsync = async () =>
{
await Task.Yield();
dialog.ShowDialog();
}
var dialogTask = showAsync();
await Task.Yield();
// now we're on the dialog's nested message loop started by dialog.ShowDialog
MessageBox.Show("The dialog is visible, click OK to close");
dialog.Close();
await dialogTask;
// we're back to the main message loop
}
That said, I can't think of any case where Task.Yield() cannot be replaced with Task.Factory.StartNew w/ proper task scheduler.
See also:
"await Task.Yield()" and its alternatives
Task.Yield - real usages?

One use of Task.Yield() is to prevent a stack overflow when doing async recursion. Task.Yield() prevents syncronous continuation. Note, however, that this can cause an OutOfMemory exception (as noted by Triynko). Endless recursion is still not safe and you're probably better off rewriting the recursion as a loop.
private static void Main()
{
RecursiveMethod().Wait();
}
private static async Task RecursiveMethod()
{
await Task.Delay(1);
//await Task.Yield(); // Uncomment this line to prevent stackoverlfow.
await RecursiveMethod();
}

Task.Yield() is like a counterpart of Thread.Yield() in async-await but with much more specific conditions. How many times do you even need Thread.Yield()? I will answer the title "when would you use Task.Yield()" broadly first. You would when the following conditions are fulfilled:
want to return the control to the async context (suggesting the task scheduler to execute other tasks in the queue first)
need to continue in the async context
prefer to continue immediately when the task scheduler is free
do not want to be cancelled
prefer shorter code
The term "async context" here means "SynchronizationContext first then TaskScheduler". It was used by Stephen Cleary.
Task.Yield() is approximately doing this (many posts get it slightly wrong here and there):
await Task.Factory.StartNew(
() => {},
CancellationToken.None,
TaskCreationOptions.PreferFairness,
SynchronizationContext.Current != null?
TaskScheduler.FromCurrentSynchronizationContext():
TaskScheduler.Current);
If any one of the conditions is broken, you need to use other alternatives instead.
If the continuation of a task should be in Task.DefaultScheduler, you normally use ConfigureAwait(false). On the contrary, Task.Yield() gives you an awaitable not having ConfigureAwait(bool). You need to use the approximated code with TaskScheduler.Default.
If Task.Yield() obstructs the queue, you need to restructure your code instead as explained by noseratio.
If you need the continuation to happen much later, say, in the order of millisecond, you would use Task.Delay.
If you want the task to be cancellable in the queue but do not want to check the cancellation token nor throw an exception yourself, you need to use the approximated code with a cancellation token.
Task.Yield() is so niche and easily dodged. I only have one imaginary example by mixing my experience. It is to solve an async dining philosopher problem constrained by a custom scheduler. In my multi-thread helper library InSync, it supports unordered acquisitions of async locks. It enqueues an async acquisition if the current one failed. The code is here. It needs ConfigureAwait(false) as a general purpose library so I need to use Task.Factory.StartNew. In a closed source project, my program needs to execute significant synchronous code mixed with async code with
a high thread priority for semi-realtime work
a low thread priority for some background work
a normal thread priority for UI
Thus, I need a custom scheduler. I could easily imagine some poor developers somehow need to mix sync and async code together with some special schedulers in a parallel universe (one universe probably does not contain such developers); but why wouldn't they just use the more robust approximated code so they do not need to write a lengthy comment to explain why and what it does?

Task.Yield() may be used in mock implementations of async methods.

Related

Better solution for sync/async problem in desktop app?

I have WinForms app where button click calls some async method of external library.
private async void button1_Click(object sender, EventArgs e)
{
await CallLibraryAsync();
}
private static async Task CallLibraryAsync()
{
var library = new Library();
await library.DoSomethingAsync();
}
The library looks like this:
public class Library
{
public async Task DoSomethingAsync()
{
Thread.Sleep(2000);
await Task.Delay(1000).ConfigureAwait(false);
// some other code
}
}
Before any asynchronous code there is some calculation simulated by Thread.Sleep call. In that case this call will block UI thread for 2 seconds. I have no option to change the code in DoSomethingAsync.
If I want to solve blocking problem, I could call the library in Task.Run like this:
private static async Task CallLibraryAsync()
{
var library = new Library();
// added Task.Run
await Task.Run(() => library.DoSomethingAsync());
}
It solves the problem, UI is not blocke anymore, but I've consumed one thread from ThreadPool. It is not good solution.
If I want to solve this problem without another thread, I can do something like this:
private static async Task CallLibraryAsync()
{
var library = new Library();
// added
await YieldOnlyAsync().ConfigureAwait(false);
await library.DoSomethingAsync();
}
// added
private static async Task YieldOnlyAsync()
{
await Task.Yield();
}
This solution works. Task.Yield() causes that method YieldOnlyAsync() always runs asynchronously and ConfigureAwait(false) causes that next code (await library.DoSomethingAsync();) runs on some ThreadPool thread, not UI thread.
But it is quite complicated solution. Is there any simpler?
Edit:
If the library method looks like this
public class Library
{
public async Task DoSomethingAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
Thread.Sleep(2000);
await Task.Delay(1000);
// some other code
}
}
UI thread would not be blocked and I do not need to do anything. But that's the problem that it is some implementation detail I do not see directly because that could be in some nuget package. When I see that the UI freezes in some situations, I may find this problem (mean CPU-bound calculation before any await in async method) just after some investigation. There is no Wait() or Result, that would be easy to find, this is more problematic.
What I would like is to be prepared for that situation if possible in some simpler way. And that's why I do not want to use Task.Run whenewer I call some third-party library.
If I want to solve blocking problem, I could call the library in Task.Run like this:
It solves the problem, UI is not blocke anymore, but I've consumed one thread from ThreadPool. It is not good solution.
This is exactly what you want to do in a WinForms app. CPU-intensive code should be moved to a separate thread to free up the UI thread. There isn't any downside to consuming a new thread in WinForms.
Use Task.Run to move it to a different thread, and wait asynchronously from the UI thread for it to complete.
To quote the Asynchronous programming article from Microsoft:
If the work you have is CPU-bound and you care about responsiveness, use async and await, but spawn off the work on another thread with Task.Run.
I have no option to change the code
People say that, but you might not actually be hamstrung thus..
Here's a simple app with the same problem you face:
It's definitely pretty sleepy:
So let's whack it into ILSpy with the Reflexil plugin loaded:
We can perhaps shorten that timeout a bit.. Right click, Edit..
Make it 1ms, Right click the assembly and Save As..
That's a bit quicker!
Have a play, NOP it out etc..
You wrote:
If I want to solve blocking problem, I could call the library in Task.Run like this:
private static async Task CallLibraryAsync()
{
var library = new Library();
// added Task.Run
await Task.Run(() => library.DoSomethingAsync());
}
It solves the problem, UI is not blocked anymore, but I've consumed one thread from ThreadPool. It is not good solution.
(emphasis added)
...and then you proceed with inventing a convoluted hack that does the same thing: offloads the invocation of the DoSomethingAsync method to the ThreadPool. So you either want to:
Invoke the DoSomethingAsync method without using any thread at all, or
Invoke the DoSomethingAsync method on a non-ThreadPool thread.
The first is impossible. You can't invoke a method without using a thread. Code runs on CPUs, not on thin air. The second can be done in many ways, with the easiest being to use the Task.Factory.StartNew method, in combination with the LongRunning flag:
await Task.Factory.StartNew(() => library.DoSomethingAsync(), default,
TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap();
This way you will invoke the DoSomethingAsync on a newly created thread, which will be destroyed immediately after the invocation of the method has completed. To be clear, the thread will be destroyed when the invocation completes, not when the asynchronous operation completes. Based on the DoSomethingAsync implementation that you have included in the question (the first one), the invocation will complete immediately after creating the Task.Delay(1000) task, and initiating the await of this task. There will be nothing for the thread to do after this point, so it will be recycled.
Side notes:
The CallLibraryAsync method violates the guideline for not exposing asynchronous wrappers for synchronous methods. Since the DoSomethingAsync method is implemented as partially synchronous and partially asynchronous, the guideline still applies IMHO.
If you like the idea of controlling imperatively the current context, instead of controlling it with wrappers like the Task.Run method, you could check out this question: Why was SwitchTo removed from Async CTP / Release? There are (not very many) people who like it as well, and there are libraries available that make it possible (SwitchTo - Microsoft.VisualStudio.Threading).
When you use async/await for I/O or CPU-bound operations, your UI thread will not blocked. In your example, you use Thread.Sleep(2000);command for simulating your CPU-bound operations but this will block your thread-pool thread not UI thread. You can use Task.Delay(2000); for simulating your I/O operations without blocking thread-pool thread.

When is it asynchronous and when is synchronous

Having read a /lot/ of documentation on the async await pattern I thought I had a pretty good handle on the pattern. I read all about async all the way then read another article that mentions 'if it runs in under 50 milliseconds don't async it'. It seems there is conflicting information and/or opinions and I have managed to just confuse myself. I have also read that Task.Yield() will force an async decorated method to run asynchronously.
Given the following code:
static async Task MethodA() {
await MethodB().ConfigureAwait(false);
}
static async Task MethodB() {
await Task.Yield();
MethodC();
}
static void MethodC() {
// do some synchronous stuff
}
static async Task Main(string[] args) {
var task1 = Task.Run(() => MethodA().ConfigureAwait(false));
var task2 = Task.Run(() => MethodB().ConfigureAwait(false));
await Task.WhenAll(new List<Task>() { task1, task2 });
}
Will MethodC run synchronously or asynchronously, I assumed asynchronously as it was called from an asynchronous method. Also, is Task.Yield necessary at all?
To be honest this is doing my head in, every article I have read delves deeper and deeper into the async await pattern with the whys and wherefores and is just adding more complexity to the question. Just looking for a simple answer.
Will MethodC run synchronously or asynchronously
Synchronously. It has a synchronous signature, so it will always run synchronously.
I assumed asynchronously as it was called from an asynchronous method
The context from which it is called is irrelevant to how MethodC will run.
is Task.Yield necessary at all
Well it will force MethodB to yield a Task before MethodC runs, but this will be incomplete until MethodC finishes, and because MethodC is synchronous (does not release the thread) it achieves nothing useful.
Just looking for a simple answer
async bubbles up the call stack, and because you are not consuming an async method here (MethodC is synchronous) you should not be using async at all.
This answer contains general info and advices, and it's not focused on the code that you posted.
Being confused while learning async-await is OK. Getting a perfect understanding of async-await without going through a confusion phase is practically almost impossible IMHO.
The await Task.Yield(), await Task.Delay(1), await Task.Run(() => { }), and .ConfigureAwait(false) are dirty hacks that people sometimes use out of frustration that an explicit way to switch imperatively to the ThreadPool context does not exist (in the standard libraries). A SwitchTo method existed in some pre-prelease .NET version, then it was removed for technical reasons, then the technical reasons were eliminated, reintroducing the method never became a high enough priority, and so it didn't happen. It may happen in the future, but don't hold your breath. It is currently available in the Microsoft.VisualStudio.Threading package, if you want it.
You don't need any of these hacks to write async-await code successfully. If you want to offload work to the ThreadPool, there is the Task.Run method that does the job perfectly.
Offloading work to the ThreadPool should be done at the "application code" level, not at the "library code" level. You can read this article to understand why exposing asynchronous wrappers for synchronous methods is not a good idea.

Why do i need to use ConfigureAwait(false) in all of transitive closure?

I am learning async/await and after I read this article Don't Block on Async Code
and this Is async/await suitable for methods that are both IO and CPU bound
I notice one Tip from #Stephen Cleary 's article.
Using ConfigureAwait(false) to avoid deadlocks is a dangerous practice. You would have to use ConfigureAwait(false) for every await in the transitive closure of all methods called by the blocking code, including all third- and second-party code. Using ConfigureAwait(false) to avoid deadlock is at best just a hack).
It appeared again in the code of the post as I have attached above.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
As my knowledge when we using ConfigureAwait(false) the rest of async method will be run in the thread pool. Why we need to add it into every await
in transitive closure? I myself just think this is the correct version as what I knew.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
It means the second use of ConfigureAwait(false) in using block is useless. Please tell me the correct way.
Thanks in advance.
As my knowledge when we using ConfigureAwait(false) the rest of async method will be run in the thread pool.
Close, but there is an important caveat you are missing. When you resume after awaiting a task with ConfigureAwait(false), you will resume on an arbitrary thread. Take note of the words "when you resume."
Let me show you something:
public async Task<string> GetValueAsync()
{
return "Cached Value";
}
public async Task Example1()
{
await this.GetValueAsync().ConfigureAwait(false);
}
Consider the await in Example1. Although you are awaiting an async method, that method does not actually perform any asynchronous work. If an async method doesn't await anything, it executes synchronously, and the awaiter never resumes because it never suspended in the first place. As this example shows, calls to ConfigureAwait(false) may be superfluous: they may have no effect at all. In this example, whatever context you were on when you enter Example1 is the context you will be on after the await.
Not quite what you expected, right? And yet, it's not altogether unusual. Many async methods may contain fast paths that don't require the caller to suspend. The availability of a cached resource is a good example (thanks, #jakub-dÄ…bek!), but there plenty of other reasons an async method might bail early. We often check for various conditions at the beginning of a method to see if we can avoid doing unnecessary work, and async methods are no different.
Let's look at another example, this time from a WPF application:
async Task DoSomethingBenignAsync()
{
await Task.Yield();
}
Task DoSomethingUnexpectedAsync()
{
var tcs = new TaskCompletionSource<string>();
Dispatcher.BeginInvoke(Action(() => tcs.SetResult("Done!")));
return tcs.Task;
}
async Task Example2()
{
await DoSomethingBenignAsync().ConfigureAwait(false);
await DoSomethingUnexpectedAsync();
}
Take a look at Example2. The first method we await always runs asynchronously. By the time we hit the second await, we know we're running on a thread pool thread, so there's no need for ConfigureAwait(false) on the second call, right? Wrong. Despite having Async in the name and returning a Task, our second method wasn't written using async and await. Instead, it performs its own scheduling and uses a TaskCompletionSource to communicate the result. When you resume from your await, you might[1] end up running on whatever thread provided the result, which in this case is WPF's dispatcher thread. Whoops.
The key takeaway here is that you often don't know exactly what an 'awaitable' method does. With or without ConfigureAwait, you might end up running somewhere unexpected. This can happen at any level of an async call stack, so the surest way to avoid inadvertently taking ownership of a single-threaded context is to use ConfigureAwait(false) with every await, i.e., throughout the transitive closure.
Of course, there may be times when you want to resume on your current context, and that's fine. That is ostensibly why it's the default behavior. But if you don't genuinely need it, then I recommend using ConfigureAwait(false) by default. This is especially true for library code. Library code can get called from anywhere, so it's best adhere to the principle of least surprise. That means not locking other threads out of your caller's context when you don't need it. Even if you use ConfigureAwait(false) everywhere in your library code, your caller will still have the option to resume on their original context if that's what they want.
[1] This behavior may vary by framework and compiler version.

is using an an `async` lambda with `Task.Run()` redundant?

I just came across some code like:
var task = Task.Run(async () => { await Foo.StartAsync(); });
task.Wait();
(No, I don't know the inner-workings of Foo.StartAsync()). My initial reaction would be get rid of async/await and rewrite as:
var task = Foo.StartAsync();
task.Wait();
Would that be correct, or not (again, knowing nothing at all about Foo.StartAsync()). This answer to What difference does it make - running an 'async' action delegate with a Task.Run ... seems to indicate there may be cases when it might make sense, but it also says "To tell the truth, I haven't seen that many scenarios ..."
Normally, the intended usage for Task.Run is to execute CPU-bound code on a non-UI thread. As such, it would be quite rare for it to be used with an async delegate, but it is possible (e.g., for code that has both asynchronous and CPU-bound portions).
However, that's the intended usage. I think in your example:
var task = Task.Run(async () => { await Foo.StartAsync(); });
task.Wait();
It's far more likely that the original author is attempting to synchronously block on asynchronous code, and is (ab)using Task.Run to avoid deadlocks common in that situation (as I describe on my blog).
In essence, it looks like the "thread pool hack" that I describe in my article on brownfield asynchronous code.
The best solution is to not use Task.Run or Wait:
await Foo.StartAsync();
This will cause async to grow through your code base, which is the best approach, but may cause an unacceptable amount of work for your developers right now. This is presumably why your predecessor used Task.Run(..).Wait().
Mostly yes.
Using Task.Run like this is mostly used by people who don't understand how to execute an async method.
However, there is a difference. Using Task.Run means starting the async method on a ThreadPool thread.
This can be useful when the async method's synchronous part (the part before the first await) is substantial and the caller wants to make sure that method isn't blocking.
This can also be used to "get out of" the current context, for example where there isn't a SynchronizationContext.
It's worth noting that your method has to be marked async to be able to use the await keyword.
The code as written seems to be a workaround for running asynchronous code in a synchronous context. While I wouldn't say you should never ever do this, using async methods is preferable in almost every scenario.
// use this only when running Tasks in a synchronous method
// use async instead whenever possible
var task = Task.Run(async () => await Foo.StartAsync());
task.Wait();
Async methods, like your example of Foo.StartAsync(), should always return a Task object. This means that using Task.Run() to create another task is usually redundant in an async method. The task returned by the async method can simply be awaited by using the await keyword. The only reason you should use Task.Run() is when you are performing CPU-bound work that needs to be performed on a separate thread. The task returned by the async method can simply be awaited by using the await keyword. You can read more in depth details in Microsoft's guide to async programming.
In an async method, your code can be as simple as:
await Foo.StartAsync();
If you want to perform some other work while the task is running, you can assign the function to a variable and await the result (task completion) later.
For example:
var task = Foo.StartAsync();
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;
With CPU-bound work that needs to be run on a separate thread, you can use Task.Run(), but you await the result instead of using the thread blocking Task.Wait():
var task = Task.Run(async () => await Foo.StartAsync());
// do some other work before waiting for task to finish
Bar();
Baz();
// now wait for the task to finish executing
await task;

Run an async function in another thread

I'm evaluating the Async CTP.
How can I begin execution of an async function on another thread pool's thread?
static async Task Test()
{
// Do something, await something
}
static void Main( string[] args )
{
// Is there more elegant way to write the line below?
var t = TaskEx.Run( () => Test().Wait() );
// Doing much more in this same thread
t.Wait(); // Waiting for much more then just this single task, this is just an example
}
I'm new (my virginal post) to Stack Overflow, but I'm jazzed that you're asking about the Async CTP since I'm on the team working on it at Microsoft :)
I think I understand what you're aiming for, and there's a couple of things you're doing correctly, to get you there.
What I think you want:
static async Task Test()
{
// Do something, await something
}
static void Main(string[] args)
{
// In the CTP, use Task.RunEx(...) to run an Async Method or Async Lambda
// on the .NET thread pool
var t = TaskEx.RunEx(Test);
// the above was just shorthand for
var t = TaskEx.RunEx(new Func<Task>(Test));
// because the C# auto-wraps methods into delegates for you.
// Doing much more in this same thread
t.Wait(); // Waiting for much more then just this single task, this is just an example
}
Task.Run vs. Task.RunEx
Because this CTP installs on top of .NET 4.0, we didn't want to patch the actual System.Threading.Tasks.Task type in mscorlib. Instead, the playground APIs are named FooEx when they conflicted.
Why did we name some of them Run(...) and some of the RunEx(...)? The reason is because of redesigns in method overloading that we hadn't completed yet by the time we released the CTP. In our current working codebase, we've actually had to tweak the C# method overloading rules slightly so that the right thing happens for Async Lambdas - which can return void, Task, or Task<T>.
The issue is that when async method or lambdas return Task or Task<T>, they actually don't have the outer task type in the return expression, because the task is generated for you automatically as part of the method or lambda's invocation. This strongly seems to us like the right experience for code clarity, though that does make things quite different before, since typically the expression of return statements is directly convertible to the return type of the method or lambda.
So thus, both async void lambdas and async Task lambdas support return; without arguments. Hence the need for a clarification in method overload resolution to decide which one to pick. Thus the only reason why you have both Run(...) and RunEx(...) was so that we would make sure to have higher quality support for the other parts of the Async CTP, by the time PDC 2010 hit.
How to think about async methods/lambdas
I'm not sure if this is a point of confusion, but I thought I'd mention it - when you are writing an async method or async lambda, it can take on certain characteristics of whoever is invoking it. This is predicated on two things:
The type on which you are awaiting
And possibly the synchronization context (depending on above)
The CTP design for await and our current internal design are both very pattern-based so that API providers can help flesh out a vibrant set of things that you can 'await' on. This can vary based on the type on which you're awaiting, and the common type for that is Task.
Task's await implementation is very reasonable, and defers to the current thread's SynchronizationContext to decide how to defer work. In the case that you're already in a WinForms or WPF message loop, then your deferred execution will come back on the same message loop (as if you used BeginInvoke() the "rest of your method"). If you await a Task and you're already on the .NET threadpool, then the "rest of your method" will resume on one of the threadpool threads (but not necessarily the same one exactly), since they were pooled to begin with and most likely you're happy to go with the first available pool thread.
Caution about using Wait() methods
In your sample you used:
var t = TaskEx.Run( () => Test().Wait() );
What that does is:
In the surrounding thread synchronously call TaskEx.Run(...) to execute a lambda on the thread pool.
A thread pool thread is designated for the lambda, and it invokes your async method.
The async method Test() is invoked from the lambda. Because the lambda was executing on the thread pool, any continuations inside Test() can run on any thread in the thread pool.
The lambda doesn't actually vacate that thread's stack because it had no awaits in it. The TPL's behavior in this case depends on if Test() actually finished before the Wait() call. However, in this case, there's a real possibility that you will be blocking a thread pool thread while it waits for Test() to finish executing on a different thread.
That's the primary benefit of the 'await' operator is that it allows you to add code that executes later - but without blocking the original thread. In the thread pool case, you can achieve better thread utilization.
Let me know if you have other questions about the Async CTP for VB or C#, I'd love to hear them :)
It's usually up to the method returning the Task to determine where it runs, if it's starting genuinely new work instead of just piggy-backing on something else.
In this case it doesn't look like you really want the Test() method to be async - at least, you're not using the fact that it's asynchronous. You're just starting stuff in a different thread... the Test() method could be entirely synchronous, and you could just use:
Task task = TaskEx.Run(Test);
// Do stuff
t.Wait();
That doesn't require any of the async CTP goodness.
There would be, if this wasn't a console application. For example, if you do this in a Windows Forms application, you could do:
// Added to a button click event, for example
public async void button1_Click(object sender, EventArgs e)
{
// Do some stuff
await Test();
// Do some more stuff
}
However, there is no default SynchronizationContext in a console, so that won't work the way you'd expect. In a console application, you need to explicitly grab the task and then wait at the end.
If you're doing this in a UI thread in Windows Forms, WPF, or even a WCF service, there will be a valid SynchronizationContext that will be used to marshal back the results properly. In a console application, however, when control is "returned" at the await call, the program continues, and just exits immediately. This tends to mess up everything, and produce unexpected behavior.

Categories

Resources