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 !
Related
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)
Either I am doing something really wrong, but the below never returns it hangs forever on the ReceiveAsync despite specifying a 1 second timeout.
I would expect it to return null value, after the time out.
/* snipped MyContainer class */
private readonly BufferBlock<byte[]> queue = new BufferBlock<byte[]>();
public async Task ExecuteAsync(CancellationToken stoppingToken)
{
// makes no difference if creating with TaskCreationOptions.LongRunning
await Task
.Factory
.StartNew(async () =>
{
while (stoppingToken.IsCancellationRequested == false)
{
// we get here OK, but no further if i use TimeSpan for delay
// without Timespan i.e. ReceiveAsync() only, it does **not** hang
var item = await
this
.queue
.ReceiveAsync(TimeSpan.FromMilliseconds(1000));
// process it, but we never get here we sleep forever
await ProcessAsync(item);
}
} /*,TaskCreationOptions.LongRunning*/);
// we get here and print the below OK
Console.WriteLine("thread created and running");
}
// this is called by the original (or some other) thread
// either if i call this or not, the above thread code still locks on ReceiveAsync
public void Add(byte[] data)
{
Console.WriteLine("adding");
this.queue.Post(data);
Console.WriteLine("done"); // gets posted OK
}
Important update - works OK if I do not specify a delay
var item = await this.queue.ReceiveAsync());
The code works OK if I remove the delay, however I do some background housekeeping every second (for packet counters etc) so this is important to wake up if nothing received within 1 second.
Other notes:
I am calling the above code from a generic dot net worker host:
public class Worker : BackgroundService
{
private readonly MyContainer containerClass;
private readonly ILogger<Worker> logger;
public Worker(MyContainer containerClass, ILogger<Worker> logger)
{
this.containerClass = containerClass;
this.logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
this.containerClass.ExecuteAsync(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
this.logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
The above is called after the worker is built by IHostBuilder and I called Host.Run().
My understanding is (which I clearly need to work on!) since I create the thread, it should run totally independently from (and not block on) the thread that created/called it... in other words it should be able to call ReceiveAsync within the thread itself without getting blocked.
Using the Task.Factory.StartNew with an async delegate creates a nested task:
Task<Task> nestedTask = Task.Factory.StartNew(async () => { //...
You are awaiting the outer task, but not the inner, so the inner task becomes a fire-and-forget task. It is possible to await both tasks in one line by using the await operator twice:
await await Task.Factory.StartNew(async () => { //...
Alternatively you can combine the two tasks in one by using the Unwrap method.
await Task.Factory.StartNew(async () => { /* ... */ }).Unwrap();
...or even better use the Task.Run method instead of the Task.Factory.StartNew, because the former understands async delegates, and does the unwrapping for you:
await Task.Run(async () => { //...
If you are interested about the differences between Task.Factory.StartNew and Task.Run, you could read an informative article here.
Thanks everyone who responded and finally to Enrico (feel free to copy/paste and i will assign the answer to you) the code was actually running OK.
A TimeoutException exception was being thrown, but wasn't caught by my code or Visual Studio.
Enabling all CLR exceptions as per https://learn.microsoft.com/en-us/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2019 the exception started being thrown.
I then handled the exception within code, and was able to proceed as my design required:
public Task ExecuteAsync(CancellationToken stoppingToken)
{
return Task
.Factory
.StartNew(async () => {
while (stoppingToken.IsCancellationRequested == false)
{
try
{
var ts = TimeSpan.FromSeconds(UpdateFrequencySeconds);
var item = await this.queue.ReceiveAsync(ts);
await ProcessAsync(item);
}
catch (TimeoutException)
{
// this is ok, timer expired
}
catch (Exception e)
{
this.logger.LogError(e.ToString());
}
UpdateCounters();
}
await StopAsync();
},
stoppingToken,
TaskCreationOptions.LongRunning,
TaskScheduler.Default)
.Unwrap();
}
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 was just experimenting to see what happens when a cold task (i.e. a Task which hasn't been started) is awaited. To my surprise the code just hung forever and "Finsihed" is never printed. I would expect that an exception is thrown.
public async Task Test1()
{
var task = new Task(() => Thread.Sleep(1000));
//task.Start();
await task;
}
void Main()
{
Test1().Wait();
Console.WriteLine("Finished");
}
Then I though perhaps the task can be started from another thread, so I changed the code to:
public async Task Test1()
{
var task = new Task(() => Thread.Sleep(1000));
//task.Start();
await task;
Console.WriteLine("Test1 Finished");
}
void Main()
{
var task1 = Test1();
Task.Run(() =>
{
Task.Delay(5000);
task1.Start();
});
task1.Wait();
Console.WriteLine("Finished");
}
But it is still blocked at task1.Wait(). Does anyone know if there is way to start a cold task after it has being awaited?
Otherwise it seems there is no point in being able to await a cold task, so perhaps the task should either be started when awaited or an exception should be thrown.
Update
I was awaiting the wrong task, i.e. the outer task returned by Test1 rather than the one newed inside it. The InvalidOperationException mentioned by #Jon Skeet was being thrown inside Task.Run however because the resulting task was not observed, the exception was not thrown on the main thread. Putting a try/catch inside Task.Run or calling Wait() or Result on the task returned by Task.Run threw the exception on the main console thread.
You're trying to start the task returned by the async method - that isn't the cold task that you started out with. Indeed, if you add some diagnostics to your Task.Run call, you'll see that an exception is thrown:
System.InvalidOperationException: Start may not be called on a promise-style task.
Here's an example showing what I think you were really trying to do:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Test
{
static void Main(string[] args)
{
// Not using Task.Delay! That would be pointless
Task t1 = new Task(() => Thread.Sleep(1000));
Task t2 = Await(t1);
Console.WriteLine(t2.Status);
Console.WriteLine("Starting original task");
t1.Start();
Console.WriteLine(t2.Status);
t2.Wait();
Console.WriteLine(t2.Status);
}
static async Task Await(Task task)
{
Console.WriteLine("Beginning awaiting");
await task;
Console.WriteLine("Finished awaiting");
}
}
Note the use of Thread.Sleep instead of Task.Delay; unless you're using the result of Task.Delay, it basically does nothing. Using Thread.Sleep is emulating real work to be done in the other task.
As for why awaiting an unstarted task doesn't throw an exception - I think that's reasonable, to be honest. It allows for situations like the above to be valid, which may in some cases make life easier. (You may create a lot of tasks before starting them, for example - and you may want to start waiting for them to finish before you start them.)
Does anyone know if there is way to start a cold task after it has
being awaited?
You still can create a cold task from an async method and start it later, if that's what you want:
class Program
{
public static async Task Test1()
{
await Task.Delay(1000);
Console.WriteLine("Test1 is about to finish");
}
static void Main(string[] args)
{
var taskOuter = new Task<Task>(Test1);
var taskInner = taskOuter.Unwrap();
Task.Run(() =>
{
Thread.Sleep(2000);
// run synchronously
taskOuter.RunSynchronously();
// or schedule
// taskOuter.Start(TaskScheduler.Defaut);
});
taskInner.Wait();
Console.WriteLine("Enter to exit");
Console.ReadLine();
}
}