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 ?
Related
I have issues understanding a detail about async programming in C#.
Lets say I have a common async method, that has a few await statements in it. Lets say I have another method, which is not async, but calls the first method.
public void DoSomething(){
DoSomethingAsync()
...
}
public async Task DoSomethingAsync(){
...
await ...
...
}
I know i could just use Wait() or some other synchronization technique, but i dont just want to throw stuff at problems without knowing what happens.
Will DoSomething continue execution before DoSomethingAsync is completed? I know that this would happen if DoSomething were to be declared async, but it isn't.
Or to be more general: Can synchronous methods continue their execution before an asynchronous sub-call has completed?
TL;DR It continues
Can synchronous methods continue their execution before an
asynchronous sub-call has completed?
Of course it can, if a synchronous method has to wait an asynchronous method to finish, what's the purpose of going asynchronous? (It can wait as well, depending on what you want to achieve)
async/await pattern in your code will create a state machine that can be recovered later. By the time your code hits await, the task you await on will be pushed to the task scheduler and might be executed in some threadpool thread. The async method returns and let the synchronous method continue.
When the task is finished, the state machine recovers the context, and everything in DoSomethingAsync after await continues. On which thread it would run? This depends on if you set ConfigureAwait and the threading model of your program. For example, for a WPF application, by default, it comes back to the main thread, and that's why wait + await can lead to deadlocks.
What happens is:
DoSomething calls DoSomethingAsync.
Then a synchronous! order starts until the first "await" is reached.
With this await, the DoSomethingAsync returns a Task object the has status "not finished yet". But as you do not assign this return value and also do nothing else special your DoSomething continues.
In the absence of the await operator this method will behave as if this call is not awaited, execution of the current method continues before the call is completed
The compiler will warn you:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs4014?f1url=%3FappId%3Droslyn%26k%3Dk(CS4014)
Can synchronous methods continue their execution before an asynchronous sub-call has completed?
As others have noted, the answer to this is "yes".
All asynchronous methods begin executing synchronously. They return a task that represents the completion of that asynchronous method. The task is completed when the asynchronous method is completed. If the asynchronous method returns a result, then the task is completed with a result value. If the asynchronous method throws an exception, then the task is completed with an exception (i.e., faulted).
However, this also means that there is are some problems with the code you've posted. Specifically, it's doing a kind of "fire and forget", and that's dangerous.
This code is just ignoring the task returned from DoSomethingAsync:
public void DoSomethingElse(){
DoSomethingAsync()
...
}
So that means it's saying "start doing something" and it's also saying "I don't care if or when that 'something' completes, and I don't care if it throws an exception". There are a couple problems with this: 1) since your app doesn't know when "something" completes, it can't know when it's safe to shut down, and 2) your app won't be notified if "something" fails.
In the vast, vast majority of scenarios, that means the app has bugs. "Fire and forget" is only appropriate when doing an operation where it doesn't actually matter if the operation fails or isn't even completed. There are very few operations where this is the case.
This is why - as a general rule - tasks should eventually be awaited. If you want to start an operation and then do other things and then await that operation to complete, that's not uncommon:
public async Task DoSomethingElseAsync() {
var task = DoSomethingAsync();
... // other synchronous/asynchronous work.
await task; // asynchronously wait for DoSomethingAsync to complete,
// and propagate any exceptions.
}
In this code:
public async Task v_task()
{
await Task.Run(() => Console.WriteLine("Hello!"));
}
public async void v1()
{
await v_task();
// some other actions...
}
public void ButtonClick()
{
v1();
Console.WriteLine("Hi!");
}
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
I mean, what should be my concerns about race conditions working with async/await? All async methods are mandatory executed in the same caller's thread? Should I use mutex on possible shared state? If yes, how could I detect what are the shared state objects?
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
Only the Console.WriteLine within the Task.Run.
I mean, what should be my concerns about race conditions working with async/await?
I suggest you start by reading my async intro, which explains how await actually works.
In summary, async methods are usually written in a serially asynchronous fashion. Take this code for example:
CodeBeforeAwait();
await SomeOtherMethodAsync();
CodeAfterAwait();
You can always say that CodeBeforeAwait will execute to completion first, then SomeOtherMethodAsync will be called. Then our method will (asynchronously) wait for SomeOtherMethodAsync to complete, and only after that will CodeAfterAwait be called.
So it's serially asynchronous. It executes in a serial fashion, just like you'd expect it to, but also with an asynchronous point in that flow (the await).
Now, you can't say that CodeBeforeAwait and CodeAfterAwait will execute within the same thread, at least not without more context. await by default will resume in the current SynchronizationContext (or the current TaskScheduler if there is no SyncCtx). So, if the sample method above was executed in the UI thread, then you would know that CodeBeforeAwait and CodeAfterAwait will both execute on the UI thread. However, if it was executed without a context (i.e., from a background thread or Console main thread), then CodeAfterAwait may run on a different thread.
Note that even if parts of a method run on a different thread, the runtime takes care of putting any barriers in place before continuing the method, so there's no need to barrier around variable access.
Also note that your original example uses Task.Run, which explicitly places work on the thread pool. That's quite different than async/await, and you will definitely have to treat that as multithreaded.
Should I use mutex on possible shared state?
Yes. For example, if your code uses Task.Run, then you'll need to treat that as a separate thread. (Note that with await, it's a lot easier to not share state at all with other threads - if you can keep your background tasks pure, they're much easier to work with).
If yes, how could I detect what are the shared state objects?
Same answer as with any other kind of multi-threaded code: code inspection.
If you call an async function, your thread will perform this function until it reaches an await.
If you weren't using async-await, the thread would yield processing until the awaited code was finished and continue with the statement after the await.
But as you are using async-await, you told the compiler that whenever the thread has to wait for something, you have some other things it can do instead of waiting, The thread will do those other things until you say: now await until your original thing is finished.
Because of the call to an async function we are certain that somewhere inside there should be an await. Note that if you call an async function that doesn't await you get a compiler warning that the function will run synchronously.
Example:
private async void OnButton1_clickec(object sender, ...)
{
string dataToSave = ...;
var saveTask = this.MyOpenFile.SaveAsync(dataToSave);
// the thread will go into the SaveAsync function and will
// do all things until it sees an await.
// because of the async SaveAsync we know there is somewhere an await
// As you didn't say await this.MyOpenfile.SaveAsync
// the thread will not wait but continue with the following
// statements:
DoSomethingElse()
await saveTask;
// here we see the await. The thread was doing something else,
// finished it, and now we say: await. That means it waits until its
// internal await is finished and continues with the statements after
// this internal await.
Note that even if the await somewhere inside SaveAsync was finished, the thread will not perform the next statement until you await SaveTask. This has the effect that DoSomethingElse will not be interrupted if the await inside the SaveAsync was finished.
Therefore normally it's not useful to create an async function that does not return either a Task or a Task < TResult >
The only exception to this is an event handler. The GUI doesn't have to wait until your event handler is finished.
Given the following method as example:
private async void F()
{
button.IsEnabled = false;
await Task.Delay(1000);
button.IsEnabled = true;
}
In this case, any code starting at await always occurs on another thread (edit: wrong) which presumably should not have access to the UI thread, similarly to desktop apps. In a similar situation, I recall having an exception such as:
The application called an interface that was marshalled for a different thread.
However, the example does not trigger any exception. Is this expected? Can I reliably write code like this?
any code starting at await always occurs on another thread (non-UI thread, right?),
No, not at all. await does not kick off other threads. I have an async intro that may help if you find this statement confusing.
What await will do is schedule the remainder of the method as a continuation to be run after the asynchronous operation completes (in this case, the asynchronous operation is just a timer firing). By default, await will capture a "context", which is SynchronizationContext.Current (or, if it is null, the context is TaskScheduler.Current). In this case, there's a UI SynchronizationContext that ensures the remainder of the async method will run on the UI thread.
Code running on the UI thread has a SynchronizationContext. You can see that by printing SynchronizationContext.Current. Before you await something that context is captured and after the await your code resumes on that context which makes sure the continuation runs on the UI thread.
To get the behavior you're referencing, where the continuation is run on a ThreadPool thread you can disable the SynchronizationContext capturing by using ConfigureAwait(false):
private async void FooAsync()
{
button.IsEnabled = false;
await Task.Delay(1000).ConfigureAwait(false);
button.IsEnabled = true;
}
This code will raise the exception you expect.
Is this expected? Can I reliably write code like this?
Yes and yes. Code using async-await will "do the right thing" by default. But if you do want to offload something to a ThreadPool thread you can use Task.Run.
I have a strange behaviour concerning wrapping asynchronous methods in C#.
It is difficult to cut out the portion of my code that has this strange behaviour, so instead I made a test project to investigate the behaviour, and this is what I have found out.
I have a test class which has an async method that is simply a wrapper of another async method: (In my original code it is a wrapper class which contains 2 objects, which it has wrapper methods for)
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
}
}
In my test program I am running the following code from an async event handler: (In my case the Loaded event, since I am using a WPF Window)
var test = new Test();
await Task.Delay(1000);
await test.Delay();
Task.Delay(1000).Wait();
test.Delay().Wait();
All is well until the last line, which never returns.
Then I tried changing the test class to the following and the last line works:
public class Test
{
public Task Delay()
{
return Task.Delay(1000);
}
}
My question is why the first scenario does not work?
I describe this deadlock scenario in detail on my blog and in an MSDN article.
By default, when you await a task, it will capture the current "context" (SynchronizationContext.Current unless it is null, in which case it captures TaskScheduler.Current). When the async method resumes, it resumes in that context.
In your case, the UI context is captured, and your async method is attempting to resume on the UI thread after the delay completes. However, it cannot resume execution because the UI thread is blocked waiting for the task to complete.
The best solution is to use async "all the way"; in other words, don't block on async code.
By default the await keyword is built to try to keep as much of the original code as possible running on the original thread (or, at least, in the same "context" as the code that runs before the await, e.g. if you were running in the thread pool previously, any thread pool thread will do).
What's happening is that all of your original code, when it can run, wants to run on the UI thread.
But you're blocking the UI thread in that Wait so it's never available to run the remainder of the code inside your async method and so complete the outer Task. I.e. there's just this little bit of code left to run in your method, after the Task.Delay task has completed:
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
//<-- This "Code" needs to run before my Task is completed
}
}
You can use ConfigureAwait(continueOnCapturedContext) to request that this not happen:
continueOnCapturedContext
true to attempt to marshal the continuation back to the original context captured; otherwise, false.
See also this old blog post by Eric Lippert, from when async was new:
The “async” modifier on the method does not mean “this method is automatically scheduled to run on a worker thread asynchronously”. It means the opposite of that; it means “this method contains control flow that involves awaiting asynchronous operations and will therefore be rewritten by the compiler into continuation passing style to ensure that the asynchronous operations can resume this method at the right spot.” The whole point of async methods it that you stay on the current thread as much as possible.
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).