While messing around with SignalR I found a behaviour that confuse me.
Calling StartCountDown from a client then make a call to Join behaves like
wait 10 seconds
Call clients CountDownStarted
Then call PlayerJoined
What I expected.
Call start CountDown, return
immediately call PlayerJoined
After 10 seconds complete CountDownStarted.
public class AHub : Hub
{
public async Task Join(string player)
{
await Clients.All.PlayerJoined(player);
}
public async Task StartCountDown()
{
await Task.Delay(10000);
await Clients.All.CountDownStarted();
}
}
This is from a SignalR Hub
This is a common misconception about the async and await pattern. Awaiting something does actually await the completion of the task.
If you want to run the task unobserved (or colloquially known as fire and forget), you could do thus
// task gets started hot and unobserved, remove the warning with a discard
_ = StartCountDownAsync();
Note : An exception that's raised in a method that returns a Task or Task<TResult> is stored in the returned task. If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown.
As a best practice, you should always await the call.
Though, you have other options. Which is to start a task, complete other tasks, and then await the completion of the original
Given
public async Task SomeTask1() { }
public async Task SomeTask2() { }
public async Task SlowApiAsync() { }
You might want
var slowApiTask = SlowApiAsync();
await SomeTask1();
await SomeTask2();
await slowApiTask;
Or if you want to run all the tasks concurrently (and yet await them all)
var slowApiTask = SlowApiAsync();
var task1 = SomeTask1();
var task2 = SomeTask2();
await Task.WhenAll(slowApiTask,task1,task2)
Related
I want to create/initialize a Task object from a async Task method without starting it directly. When searching online I only find answer with Task created from void methods.
This is the task method I want to execute. As I need to do some web requests async, the method needs to be async. I want to do exception handling as well, so it can't be an async void.
private async Task WebRequestTask()
{
try
{
string ResponseText = await httpClient.GetStringAsync("https://fakeurl.com");
// process response code
}
catch (Exception ex)
{
// handle error
}
}
This is my main method where I want to create the task:
private void StartTask()
{
TokenSource = new CancellationTokenSource();
Task RequestTask = ... // here I want to initialize the task without starting
// chain continuation tasks to RequestTask
RequestTask.Start();
}
I've tried following solutions but nothing answers my need:
Solution 1
Task RequestTask = new Task(WebRequestTask);
Task RequestTask = WebRequestTask;
-> both cause a compiler error
Solution 2
Task RequestTask = Task.Run(WebRequestTask);
-> this start the task async and the current method continues (but here it could be possible an exception is thrown before the continuation tasks are chained)
Solution 3
Task RequestTask = WebRequestTask();
-> this start the task synchronously and chaining happens after the task is finished
Solutions 4
Task<Task> OuterTask = new Task<Task>(LoginToAzure);
await LoginAzureTask.Unwrap();
-> this start the outer task but the inner task is never called
How can I attach this Task method to an Task object, so that I can first attach continuation tasks/set some options and then start it? When it's possible, I'd like to use the cancellation token as well.
I want to create/initialize a Task object from a async Task method without starting it directly.
The best way to do this is to use delegates. E.g.:
private void StartTask()
{
TokenSource = new CancellationTokenSource();
Func<Task> taskFactory = () => WebRequestTask(TokenSource);
// chain continuation tasks
Task task = taskFactory(); // Start the task
... // await the task or save it somewhere
}
Side note: I strongly recommend implementing "chain continuation tasks" using await rather than ContinueWith. await is a clean and safe approach; ContinueWith is a low-level, dangerous method.
I want to do exception handling as well, so it can't be an async void.
Since you are handling the error inside WebRequestTask() that doesn't really matter.
The preferred option would be to make StartTask an async Task but if that isn't possible, make it async void. That takes care of the "without starting" requirement too.
So, keep it simple:
private async void StartTask()
{
TokenSource = new CancellationTokenSource();
try
{
await WebRequestTask(TokenSource.Token);
// here I want to initialize the task without starting -- irrelevant in an async void
await otherTask(); // continuation(s)
}
catch()
{
// handle residual errors
}
}
The asynchronous methods that are implemented with the async keyword are creating "hot" Tasks, in other words Tasks that are already started. You can defer the execution of an async method by wrapping it in another Task, thus creating a nested Task<Task>, like this:
{
TokenSource = new CancellationTokenSource();
var token = TokenSource.Token;
Task<Task> taskTask = new Task<Task>(() => WebRequestAsync(token));
Task task = taskTask.Unwrap(); // The task is not started yet
// Chain continuations to task
taskTask.RunSynchronously(TaskScheduler.Default);
// The task is now started
}
private async Task WebRequestAsync(CancellationToken cancellationToken)
{
try
{
string responseText = await httpClient.GetStringAsync(
"https://fakeurl.com", cancellationToken);
// Process response code
}
catch (Exception ex)
{
// Handle error
}
}
The taskTask variable is the wrapper that represents just the execution of the WebRequestAsync method, not the completion of the Task that this method creates. The wrapper task is completed immediately after calling the RunSynchronously method, and after that point your code will have no use for it. The task variable "unwraps" the wrapper, and represents the actual asynchronous web request. It is completed when the asynchronous operation completes.
As you can see this technique is rather cumbersome. You'll rarely see it in application code, because pure async-await composition is much more convenient to use.
If an asynchronous call is made within a using statement, and the result of the call is processed asynchronously (i.e. the method within which this happens is async and returns before the result is loaded and processed), can the using statement go out of scope?
In other words, is it safe to do something like this:
async void LoadAndProcessStuff()
{
using(var ctx = CreateDBContext()){
someResource.LoadStuffsAsync().ForEachAsync(stuff => ctx.Stuffs.Add(stuff));
}
}
or
async void LoadAndProcessStuff2()
{
using(var ctx = CreateDBContext()){
ctx.Stuffs.Select(stuff => someResource.LoadMoreStuffsAsync(stuff))
.ForEachAsync(stuff => ctx.Stuffs2.AddRange(stuff.Result));
}
}
Or could ctx be Disposed by the time the ForEachAsync is called and cause an exception?
In an async method, the "using" keyword should be safe. The compiler just rewrites it as a "finally" expression, which works like all other exception handling in async methods. Note that Dispose() should NOT block or be long running, it should just release resources - unless you want to cripple your server.
This is an easy test case for the safe case:
using System;
using System.Threading.Tasks;
namespace so {
sealed class Garbage : IDisposable {
public void Dispose() {
Console.WriteLine("Disposing Garbage");
}
}
// Garbage is safely Disposed() only after delay is done
class Program {
public static async Task Main() {
using (Garbage g = new Garbage()) {
Console.WriteLine("Delay Starting");
await Task.Delay(1000);
Console.WriteLine("Delay Finished");
}
}
}
}
However, if you have a non-async method that is returning a Task instead of awaiting it, it may be unsafe. That is because synchronous methods are only called once. There is no coroutine or state machine generated by compiler, so Dispose() HAS to be called right away - potentially while the Task is still running.
public Task DoWorkAsync()
{
using (var service = new Service())
{
var arg1 = ComputeArg();
var arg2 = ComputeArg();
// NOT SAFE - service will be disposed
// There is a high-probability that this idiom results
// in an ObjectDisposedException
return service.AwaitableMethodAsync(arg1, arg2);
}
}
For ref: http://www.thebillwagner.com/Blog/Item/2017-05-03-ThecuriouscaseofasyncawaitandIDisposable
If you want to safely do async/parallel stuff (and background stuff), the best is to use Tasks, async/await and ConfigureAwait. And keep in mind that it's always better to run the stuff inside a using before the execution leaves the method, so you have to think and encapsulate your code accordingly.
Here are some examples of what you may want to do :
execute a long running task asynchronously
public async Task ParentMethodAsync() {
DoSomeSyncStuff();
await DoBigStuffAsync();
DoSomeSyncStuffAfterAsyncBigStuff();
}
public async Task DoBigStuffAsync() {
await Task.Run(() => {
DoBigSyncStuff();
});
}
With that code your execution will be :
DoSomeSyncStuff
then DoBigSyncStuff will be run asynchronously inside
DoBigStuffAsync
ParentMethodAsync will wait for this to complete before running
DoSomeSyncStuffAfterAsyncBigStuff
execute a long running task asynchronously on background
public async Task ParentMethodAsync() {
DoSomeSyncStuff();
// original context/thread
await DoBigStuffAsync();
// same context/thread as original
DoSomeSyncStuffAfterAsyncBigStuff();
}
public async Task DoBigStuffAsync() {
// here you are on the original context/thread
await Task.Run(() => {
// this will run on a background thread if possible
DoBigSyncStuff();
}).ConfigureAwait(false);
// here the context/thread will not be the same as original one
}
Here same running order and blocking points, but with ConfigureAwait(false) you specify that you don't care synchronizing on the original context. Note that ParentMethodAsync context/thread is not impacted
execute stuff asynchronously and continue stuff at the same time
public async Task ParentMethodAsync() {
DoSomeSyncStuff();
Task bigStuffTask = DoBigStuffAsync();
DoSomeSyncStuffBeforeEndOfBigStuff();
await bigStuffTask;
DoAnotherSyncStuffAfterAsyncBigStuff();
}
public async Task DoBigStuffAsync() {
await Task.Run(() => {
DoBigSyncStuff();
});
}
With that code your execution will be :
DoSomeSyncStuff
then DoBigSyncStuff will start running asynchronously inside
DoBigStuffAsync
ParentMethodAsync will not wait for bigStuffTask to complete and will run DoSomeSyncStuffBeforeEndOfBigStuff
bigStuffTask (or DoBigStuffAsync) may complete before or after
DoSomeSyncStuffBeforeEndOfBigStuff does
the await bigStuffTask will force ParentMethodAsync to wait for
bigStuffTask to complete before running
DoAnotherSyncStuffAfterAsyncBigStuff
execute multiple stuff asynchronously
public async Task ParentMethodAsync() {
DoSomeSyncStuff();
Task bigStuffTask = DoBigStuffAsync();
Task bigStuff2Task = DoBigStuff2Async();
await Task.WhenAll(bigStuffTask, bigStuff2Task);
DoAnotherSyncStuffAfterAsyncBigStuff();
}
public async Task DoBigStuffAsync() {
await Task.Run(() => {
DoBigSyncStuff();
});
}
With that code your execution will be :
DoSomeSyncStuff
then DoBigSyncStuff will start running asynchronously inside DoBigStuffAsync
then bigStuff2Task will start running asynchronously inside DoBigStuff2Async
ParentMethodAsync will wait for bigStuffTask and bigStuff2Task to complete
once both completed, DoAnotherSyncStuffAfterAsyncBigStuff will run (synchronously)
execute stuff and don't wait/care for it to complete (Fire-and-forget)
public async Task ParentMethodAsync() {
DoSomeSyncStuff();
Task bigStuffTask = DoBigStuffAsync();
Task bigStuff2Task = DoBigStuff2Async();
// this one is fired and forgotten
DoFireAndForgetStuffAsync();
await Task.WhenAll(bigStuffTask, bigStuff2Task);
DoAnotherSyncStuffAfterAsyncBigStuff();
}
public async Task DoBigStuffAsync() {
await Task.Run(() => {
DoBigSyncStuff();
});
}
public async void DoFireAndForgetStuffAsync() {
Task.Run(() => {
try {
DoSomeFireAndForgetStuff();
} catch (Exception e) {
// handle your exception
}
});
}
With that code your execution will be :
DoSomeSyncStuff
then DoBigSyncStuff will start running asynchronously inside DoBigStuffAsync
then bigStuff2Task will start running asynchronously inside DoBigStuff2Async
then DoSomeFireAndForgetStuff will start running asynchronously
and your code will never care to know if it completed or not
afterwards
ParentMethodAsync will wait for bigStuffTask and bigStuff2Task to complete
once both completed, DoAnotherSyncStuffAfterAsyncBigStuff will run (synchronously)
Please note that async void method should be used wisely and should always have their own exception handling inside.
Otherwise, if an exception is thrown, as you have no way to control when and what the execution context will be in, you may end up with unexpected and random crashes.
There are other stuff you could learn from there for example, of with youtube livecode (e.g. this one from Xamarin Evolve in which James Clancey explains the thread aspects through a simple xamarin app)
I hope it will help you achieve what you want to !
How can I make async/await method in repository? Should I use Task.Run?
public virtual void Add(T entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_context.Entry(entity);
Entities.Add(entity);
}
catch (DbEntityValidationException dbEx)
{
...
}
}
Using async/await is only useful if your function is async and you expect that the clients that call your functions are async (and their clients etc).
The reason is, because calling an async function does not mean that the function is performed. It means that a Task is scheduled to run the function performed by a thread in a pool of available threads. After the task is scheduled your function can continue with the next statement. When it needs the result of the scheduled task it awaits until the scheduled task is finished.
The advantage above starting a thread yourself is that this saves the overhead to start a new thread and do the cleanup afterwards. The disadvantage is that you are not certain that a thread is available the moment you schedule the task.
If your function is not declared async you still can schedule a task using Task.Run( () => OtherFunction(...)), but you can't await for it. To wait for the task to finish you have to call Task.Wait(...). In the meantime the thread that called your function can't continue. If this thread is the UI thread you'll notice this because your UI is not responsive.
So if you want to make proper use of other async functions, its best to declare your function async and return Task instead of void and Task<TResult> instead of TResult. Call the other async function, do other things and await the task before returning. The clients need to be async and return Task / Task<TResult>. The only async client that may return void is the event handler.
Example:
public async void button1_clicked(object sender, ...)
{
Task<int> task1 = this.DoSomethingAsync(...);
// while task1 is running you can do other things
// you can even schedule another task:
Task task2 = this.DoSomethingElseAsync(...);
// do other things. After a while you need the result of task1:
int task1Result = await task1;
// or if you want to await until both tasks are finished:
await Task.WhenAll(new Task[]{task1, task2});
int task1Result = task1.Result;
}
private async Task<int> DoSomethingAsync(...)
{
// schedule another async task and await:
await DoSomethingElseAsync(...);
return 42;
}
private async Task DoSomethingElseAsync(...)
{
// do something really important:
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
}
If you don't want to force your clients to be async, consider creating two versions, one async and one non-async. This is quite common. See definitions in Files, Streams, DbConnections etc.
Why the tasks are executed before Task.WhenAll??
If you see here, from the below code snippet, first Console.WriteLine("This should be written first.."); should be printed because I am awaiting the tasks beneath to it..
But if you see the output result, the Tasks method result is being printed before the above statement. Ideally, the tasks method should be executed when I await them, but it seems that- the tasks methods are executed the moment I add them in tasks list. Why is it so?
Would you please do let me know why is this happening??
Code:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.FromResult(0);
Console.WriteLine(number);
}
Output
When you call an async method you get a "hot" task in return. That means that the task already started running (and maybe even completed) before you get to await them. That means that it's quite possible for the tasks to run and complete before the call to Task.WhenAll.
In your case however, while the PrintNumber is marked async it isn't asynchronous at all since you're using Task.FromResult. The synchronous part of an asynchronous method (which is the part until you await an asynchronous task) is always executed synchronously on the calling thread and is done before the call returns. When you use Task.FromResult you get a completed task so all your method is just the synchronous part and is completed before the call returns.
When you await a completed task (as is created by Task.FromResult, it completes synchronously. This means that in your example, nothing is actually happening asynchronously, which explains the order of execution.
If instead, you were to
await Task.Yield();
you'd see output more in line with your expectations.
Task.FromResult won't cause yield and the task will be executed on the same thread. To achieve what you want you can do this:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.Yield();
Console.WriteLine(number);
}
If you want a Task or tasks to run after something else, its easiest to write your code accordingly.
public static async Task Test()
{
Console.WriteLine("This should be written first..");
// These should be printed last..
await Task.WhenAll(new[]
{
PrintNumber(1),
PrintNumber(2),
PrintNumber(3)
});
}
following on from your comment.
So we have some functions,
async Task<Customer> GetRawCustomer()
{
...
}
async Task<string> GetCity(Customer customer)
{
...
}
async Task<string> GetZipCode(Customer customer)
{
...
}
We could use them like this
var rawCustomer = await GetRawCustomer();
var populationWork = new List<Task>();
Task<string> getCity;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getCity = GetCity(rawCustomer);
populationWork.Add(getCity);
}
Task<string> getZipCode;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getZipCode = GetZipCode(rawCustomer);
populationWork.Add(getZipCode);
}
...
await Task.WhenAll(populationWork);
if (getCity != null)
rawCustomer.City = getCity.Result;
if (getZipCode != null)
rawCustomer.ZipCode = getZipCode.Result;
I think I missunderstanding the behaviour of async await in c#.
I have two methods that return a Task defined like
public async Task Name()
{
await AsyncOperation()
}
Imagine AsyncOperation() like an PostAsync of HttpClient.
Now I call them inside some other methods
public asyn Task Method()
{
await Name1(() => { "bla bla"});
await Name2();
Console.WriteLine("Continue");
}
This works as expected to me. Waits until Name1() and Name2() finish and then continues.
Now I need to nest Name1() and Name2(). In fact Name1() is a Please Wait Window that recieve as lambda parameters a slow operation, while Name2() is a slow download of a file. I want the Plese Wait window appears while the file is downloaded.
So I try something like this:
public asyn Task Method()
{
await Name1( async ()=>
{
await Name2();
}
Console.WriteLine("Continue");
}
In this case the execution doesnt wait untile Name2() finished. Why this happen and await doesnt wait?
Update
This is the logic behind the method of please wait. It shows a Please Wait message using Mahapps Dialogs, executes the code that recieves by the lambda, and then close the please wait message.
public static async Task Name1(Action longOperation)
{
_progressController = await _metroWindow.ShowProgressAsync("Please wait...");
await Task.Run(() => longOperation());
await _progressController.CloseAsync();
}
The Name1 method takes a delegate and returns a Task<T> where T is the type returned by the delegate. In your case, the delegate returns Task, so we get Task<Task> as the result. Using await waits only for the completion of the outer task (which immediately returns the inner task) and the inner task is then ignored.
You can fix this by dropping the async and await in the lambda function.
Also, take a look at Asynchronous Gotchas in C#.