What's the difference between:
public class Worker
{
public static void Execute()
{
ExecuteInBackgroundThread().Wait();
}
private static Task ExecuteInBackgroundThread()
{
return Task.Run(() =>
{
// do some long running operation
});
}
}
and
public class Worker
{
public static void Execute()
{
ExecuteInBackgroundThread().Wait();
}
private static async Task ExecuteInBackgroundThread()
{
await Task.Run(() =>
{
// do some long running operation
});
}
}
I noticed that calling the second version of Worker.Execute() from the UI thread my Windows Phone app gets stuck.
Instead, using the first version everything seems to work fine.
Is the second version of ExecuteInBackgroundThread actually returning a Task<T> that can be awaited? But if that is not the case, should the compiler not give an error saying that we are not returning anything?
First of all, the real reason your app gets stuck is that you have a deadlock. That's because you're using Task.Wait which is blocking the UI thread on a task that is waiting for the UI Thread to complete.
That happens because there's only a single UI thread and so there's a SynchronizationContext that only uses that specific thread.
You can fix your deadlock by using ConfigureAwait(false), which doesn't use the SynchronizationContext:
private static async Task<T> ExecuteInBackgroundThread<T>()
{
await Task.Run(() =>
{
// do some long running operation
}).ConfigureAwait(false);
}
Other than that, both options are pretty much the same as long as there's no more code in ExecuteInBackgroundThread which is outside of the call to Task.Run. The first option is slightly faster because you're using the task from Task.Run directly. The second option adds another redundant async layer (including a state machine, etc.) on top.
Conclusion: You should use the first option. But don't use Wait which not only blocks your threads, but may result in a deadlock in some cases.
Let's see what calling Execute for each version does:
The first version calls ExecuteInBackgroundThread which immediately returns a Task. Then Execute blocks until the returned task is finished.
The second version calls ExecuteInBackgroundThread which creates a Task and schedules a continuation which will be executed when the task if finished, and returns another task. Then Execute blocks until the returned task is finished.
The difference is that the second version has a continuation scheduled because of the await keyword. The effect of it depends on the synchronization context of the thread in which you call Execute. When you are on a UI thread the second version will deadlock, because the continuation is scheduled on the UI thread which is blocked because of the call to Wait.
If you are using a console application then there won't be a deadlock because the default synchronization context uses the thread pool to execute the continuations.
Related
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
When doing await the Task could or could not be executed on the same thread. Usually, we just need to take this fact into design consideration. But I would like to do a test specifically for the thread change scenario - how do I ensure the rest of the async method (after await) is run on a different thread?
Possible solution:
[Test]
public void TestForThreadChange()
{
int threadIdBefore, threadIdAfter = 0;
async Task AsyncFunction()
{
Console.WriteLine($"before - {threadIdBefore = Thread.CurrentThread.ManagedThreadId}");
await Task.Yield();
Console.WriteLine($"after - {threadIdAfter = Thread.CurrentThread.ManagedThreadId}");
}
AsyncFunction().Wait();
Assert.That(threadIdBefore, Is.Not.EqualTo(threadIdAfter));
}
how do I ensure the rest of the async method (after await) is run on a different thread?
First, ensure that you have call the method being tested from a thread-pool context. Some unit test frameworks do provide a single-threaded context. If that is the case, you'll want to wrap your testing code in an await Task.Run(() => ...).
Then, mock the method being awaited and ensure it does an await Task.Yield(); this will ensure the await in the method under test will get an incomplete task, causing it to resume on a thread pool thread.
If you want to be absolutely sure that it resumes on a different thread pool thread, you'll need to block your unit test method on the method being tested, so that the current thread pool thread is blocked and not used to resume the method being tested.
You can't. Async pattern is designed to simplify the async (duh) code at the expense of some control. If you need to control thread creation, use Thread/ThreadPool.
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
Is there a C# equivalent of F#'s StartImmediate which can be executed on a Task? I have a situation where I need to await a function sometimes, but other times I just want the method to call back to the UI thread without using await.
I want to avoid async void if possible.
Example:
public async void DoSomething()
{
//before runs on UI thread
await OtherThing();
//after runs on UI thread
}
public async Task DoSomethingElse()
{
//before runs on UI thread
await OtherThing();
//I want this to run on the UI thread
}
public void CallDoSomething()
{
DoSomething(); //no need to await, returns to the UI thread to continue execution
DoSomethingElse();//Doesn't return to the UI thread to continue execution
DoSomethingElse().???(); // how to return to the UI thread for the async callback?
}
In F# this would look like this:
let CallDoSomething () =
//more code here
async {
//runs on the current thread
do! OtherThing()
//runs on the current thread
} |> Async.StartImmediate
//code here doesn't wait for the async to finish
So, when looking at your code example. You have an async method that return a Task. You're calling that method, and then calling Start on the resulting task (without calling await). That will throw an exception at runtime. The task is already started just by calling the method. Starting an already running task (or a completed task, if it completed before it returned) will throw an exception. You can only Start a task created using the Task constructor, which you're not using.
You also claim, in comments, that you are not in the UI thread when you return after calling DoSomethingElse. That is false. The code will run in the UI thread.
You also imply that the await in DoSomethingElse won't marshal the callback to the UI thread, but it will. Since it was called from the UI thread, it captured the UI context, and uses it when calling await.
So in short, you need to do nothing except remove the call to Start.
The one problem you do have, if you structure your code like this, is that you will never know if your code errors out, as there is nothing to observe any exceptions. There are two ways you could address this. One would be for each of the methods you call in this manor to consider themselves "top level methods" and handle all exceptions instead of every throwing any.
The other option would be to store all of the tasks called in this manner and await Task.WhenAll those tasks, so you can observe any errors when they all finish.
Did you try the RunSynchronously() method of the Task class ?
I have a Task that I am starting and wish to wait for completion in a WPF app. Inside this task I invoke an Action on the dispatcher.
If I use Task.Wait() it appears to hang as if the method never finished. Also, breakpoints inside the Dispatcher.Invoke are never hit.
If I use Task.RunSyncronously() it appears to work correctly and breakpoints inside the Dispatcher are hit.
Why is there a difference?
Code sample below:
public void ExampleMethod()
{
// When doing the following:
var task = new Task(LoadStuff);
// This never returns:
task.Start();
task.Wait();
// This version, however, does:
task.RunSyncronously();
}
private void LoadStuff()
{
ObservableCollection<StuffObj> stuff = Stuff.Load(arg1, true);
DispatchHelper.RunOnDispatcher(() =>
{
...
});
}
public static class DispatchHelper
{
public static void RunOnDispatcher(Action action)
{
Application.Current.Dispatcher.Invoke(action);
}
}
Yes, there's a major difference. If you use RunSyncronously you just run the task in the UI thread. If you start it up in a background thread and us Wait then the code is running in a background thread and the UI thread is blocked. If the code within that task is invoking to the UI thread, and the UI thread is being blocked (by the Wait) then you've created a deadlock, and the application will remain frozen.
Note that if you used, RunSyncronously on that task from a non-UI thread, and the UI thread was being blocked by something else, you would still see the deadlock.
Now, as for what you should do, there are really two options here:
The task itself doesn't actually take a long time, and it really should run in the UI thread rather than in a background thread. The UI thread won't be frozen (temporarily) for long enough to be a problem doing all of this work directly in the UI. If this is the case, you probably shouldn't even make it a Task, just put the code in a method and call the method.
The task does take a long time to run, and then it updates the UI after doing that work. If that is the case then it's important that it not be RunSyncronously but started in a background thread. In order to prevent your entire application from deadlocking it will mean that you'll need to not block the UI thread through a Wait call. What you need to do if you have some code that you want to run after the task finishes, is to add a continuation to the task. In C# 4.0 this could be done by calling ContinueWith on the task, and adding in a delegate to be run. In C# 5.0+ you could instead await on the relevant task (rather than Waiting on it, which is actually a big difference) and it will automatically wire up the remainder of the method to run as a continuation for you (in effect it is syntactic sugar for an explicit ContinueWith call, but it's a very useful one).