Why is await exiting? - c#

Given the following code:
public async Task Send() // part of Sender class
{
// sync code
}
// //
private async Task HandleMessage()
{
// await sender.Send(); // exits HandleMessage immediately
sender.Send().Wait(); // works as expected, waiting to complete
DoOtherStuff(); // doesn't get hit with await
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
public void RunRecurringTask(Action action, RecurringTaskRunResult result)
{
action();
result.DoStuff();
}
I thought that await tells the thread to come back when the awaited thing is complete, but it looks like for some reason that's not happening: the remaining code is never hit and everything just... stops. What could be causing this?
This is a console application in an Azure WebJob, for what it's worth. When Wait is used, I get the expected results, however with await, the job just completes.

You should never do async void unless you are writing a event handler. A Action with the async modifier is a async void method. You need to make the argument a Func<Task> and then do await action() in your RunRecurringTask
private async Task HandleMessage()
{
await sender.Send();
DoOtherStuff();
return;
}
RunRecurringTask(async () => await HandleMessage(), result);
//You also could do
//RunRecurringTask(() => HandleMessage(), result);
public async Task RunRecurringTask(Func<Task> action, RecurringTaskRunResult result)
{
await action();
result.DoStuff();
}
If you had other methods that where not marked with async you will need to change all of them up the call stack till you get to the entry point from the SDK. The SDK understands how to handle functions with a async Task return type since the 0.4.0-beta version.

Related

Task.Delay not delaying async method

I'm trying to create multiple tasks, run them in parallel, and wait for them all to finish.
public class SimulationManager
{
public List<Task> Simulations = new List<Task>();
public void AddSimulation(SimulationParameters parameters)
{
Simulations.Add(new Task(async () => await new Simulation().Simulate()));
}
public async Task StartSimulations()
{
Simulations.ForEach(s => s.Start());
await Task.WhenAll(Simulations);
Console.WriteLine("All tasks finished");
}
}
The task itself delays the execution by one second and then prints out a message.
public class Simulation
{
public async Task Simulate()
{
Console.WriteLine("Simulating");
await Task.Delay(1000);
}
}
I would expect the output to be:
Simulating
All tasks finished
Instead, I get:
All tasks finished
Simulating
If I replace await Task.Delay(1000) with Thread.Sleep(1000) it works as expected.
Why is the task being marked as completed without actually being completed?
If I read the status of the task before and after Task.WhenAll, it is awaiting correctly. The problem is then that Task.Delay is not delaying the execution even though the method is async.
Simulations.ForEach(s => s.Start());
Console.WriteLine(Simulations.First().Status); // prints "WaitingToRun"
await Task.WhenAll(Simulations);
Console.WriteLine(Simulations.First().Status); // prints "RanToCompletion"
Console.WriteLine("All tasks finished");
Remove redundant Task wrapper - this is what causing the issues.
Store simulations as a function returning Task and start simulation explicitly by invoking it.
public class SimulationManager
{
public List<Func<Task>> Simulations = new List<Func<Task>>();
public void AddSimulation(SimulationParameters parameters)
{
Simulations.Add(() => new Simulation().Simulate());
}
public async Task StartSimulations()
{
var tasks = Simulations.Select(simulate => simulate()).ToArray();
await Task.WhenAll(tasks);
Console.WriteLine("All tasks finished");
}
}
You are waiting on the wrong thing. Here is a fixed version
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskSimulateEarlyReturn
{
public class Simulation
{
public async Task Simulate()
{
Console.WriteLine("Simulating");
await Task.Delay(1000);
Console.WriteLine("Finished Simulating");
}
}
public class SimulationManager
{
public List<Task<Task>> Simulations = new List<Task<Task>>();
public void AddSimulation()
{
Simulations.Add(new Task<Task>(async () => await new Simulation().Simulate()));
}
public async Task StartSimulations()
{
for(int i=0;i<4;i++)
{
AddSimulation();
}
Simulations.ForEach(s => s.Start());
await Task.WhenAll(Simulations.Select(x=>x.Unwrap()).ToArray());
Console.WriteLine("All tasks finished");
}
}
class Program
{
static void Main(string[] args)
{
var man = new SimulationManager();
man.StartSimulations().Wait();
Thread.Sleep(1000);
}
}
}
The key ingredient is that you are creating a task with an async method inside it. Implicitely an async method will always return a task which is complete when the async method has completed. Since you are wrapping the Task with a Task you are waiting on the outer unrelated task which completes immediately hence your race condition.
async void F1()
{
await Task.CompletedTask;
}
async Task F2()
{
await Task.CompletedTask;
}
Both async methods are identical but the F1 method which does return void will still return a task under the hood or else you would not be able to await it. This is just a compiler trick to make "old" code work with async methods, without packing async as special method signature on top of it.
You are creating then tasks like this:
var t = new Task(F1);
var t1 = new Task<Task>(F2);
But now you have wrapped the async task returning method inside an outer task which will be complete as soon as the first sync part of the async method has completed.
What you need to do is to wait on the inner task which can be conveniently done with Task.Unwrap which is there exactly for that reason.
If you remove the Task.Unwrap call in my sample you are waiting on the outer task and you are getting your race condition back.
In general I would not use async/await except to free up the UI thread. async/await is inherently single threaded because you can await always only one task. If used this way (Task.WhenAll is kind of cheating) the one and only feature you get is thread hopping. At a single point in time your async await things will run on one thread which might change before during and after the await depending on the Synchronization Contexts.

Dispatcher.CurrentDispatcher causes ReactiveUI call to hang

Calling .Execute() on a ReactiveCommand hangs or creates a deadlock in the example below. Why is this happening, and what is the best way to avoid it?
The error only occurs when Dispatcher.CurrentDispatcher is called. The obvious answer, to not call it, is unfortunately not an option in the larger project.
I have nuget packages reactiveui-core and reactiveui-winforms in the project, both v7.4.0. I'm running nunit tests from Visual Studio with Resharper.
The code is an NUnit test fixture, note the TimeoutAfterAsync is a helper method to cancel the test after a certain timeout, the behaviour is observed without this wrapper
[TestFixture]
public class ReactiveCommandTests
{
private static async Task<bool> ExecuteCommand()
{
await Task.Delay(1000);
return true;
}
public static ReactiveCommand<Unit, bool> Command = ReactiveCommand.CreateFromTask(ExecuteCommand);
public static ReactiveCommand<Unit, bool> CommandOnTaskpoolScheduler = ReactiveCommand.CreateFromTask(ExecuteCommand, outputScheduler: RxApp.TaskpoolScheduler);
public static ReactiveCommand<Unit, bool> CommandAfterDispatcherInvoked = ReactiveCommand.CreateFromTask(ExecuteCommand);
[Test, Order(1)]
public async Task Test()
{
//THIS WORKS
try
{
await TimeoutAfterAsync(
Command.Execute(),
TimeSpan.FromSeconds(5),
"control");
}
catch (TimeoutException)
{
Assert.Fail("Control case timed out (not expected)");
}
}
[Test, Order(2)]
public async Task Test_CreateCommandAfterDispatcherCall()
{
//This line causes unwanted behaviour
var x = Dispatcher.CurrentDispatcher;
//THIS FAILS
try
{
await TimeoutAfterAsync(
CommandAfterDispatcherInvoked.Execute(),
TimeSpan.FromSeconds(5),
"after dispatcher creation");
}
catch (TimeoutException)
{
Assert.Fail("Executing commandAfterDispatcherInvoked timed out (expected, but not understood");
}
}
[Test, Order(3)]
public async Task Test_CreateCommandWithThreadpoolScheduler()
{
//This line causes unwanted behaviour
var x = Dispatcher.CurrentDispatcher;
//THIS WORKS AGAIN (using ThreadpoolScheduler when creating ReactiveCommand)
try
{
await TimeoutAfterAsync(
CommandOnTaskpoolScheduler.Execute(),
TimeSpan.FromSeconds(5),
"after dispatcher creation, with thread pool");
}
catch (TimeoutException)
{
Assert.Fail("ThreadpoolScheduler case timed out (not expected)");
}
}
private static async Task<TResult> TimeoutAfterAsync<TResult>(IObservable<TResult> observable,
TimeSpan timeout,
string context)
{
var task = observable .ToTask();
var result = await Task.WhenAny(task, Task.Delay(timeout));
if (result == task)
{
// Task completed within timeout.
return task.GetAwaiter().GetResult();
}
else
{
// Task timed out.
throw new TimeoutException(context);
}
}
}
Dispatcher.CurrentDispatcher is a fun one; it creates a dispatcher for the current thread if it doesn't already have one! This causes a problem for unit tests, since the new dispatcher is created for a thread pool thread, which isn't STA and doesn't have a message pump.
The ideal solution is to not call CurrentDispatcher. Ever. Use await or IProgress<T> or (if you must) SynchronizationContext to communicate results/progress/events to the UI thread. These abstractions are much easier to create a test environment for.
But for now, you may be able to use WpfContext, an old utility type that was included in early versions of the Async CTP. WpfContext.Run will take a delegate, create a dispatcher context for the current thread, and execute the delegate within that dispatcher context, pumping its messages until the asynchronous operations have completed.

Exception-Handling asynchronous programming

I have some code in here. This is simplified version of a real class:
public class Delayer
{
//it has to be unawaitable
public async void Execute(Action action)
{
await Task.Delay(10).ConfigureAwait(false);
action.BeginInvoke(null, null); //action.Invoke();
}
}
I use it:
private static Task TestFoo()
{
throw new Exception();
}
delayer.Execute(async () =>
{
//do something else
await TestFoo().ConfigureAwait(false);
});
I can't hadle this exception by passing Execute method into try/catch and I can't do it by passing action.BeginInvoke(null, null) into try/catch as well. I can handle it if only I surround async lambda with try/catch when pass it to Execute method.
My question is: why is async lambda executed with await? Because if it weren't executed with await, exception would be swallowed.
I want Execute method to swallow all exceptions thrown from an action. Any ideas how to do it? What do I do wrong?
Addition:
The behavior of Execute must be like "just a fire and forget operation".
Edit
If your really, really want a Fire and Forget method the only thing to do is to
catch all exceptions in the Execute method. But you have to accept an awaitable task if you want to be able to catch exceptions instead of using BeginInvoke on a non-awaitable Action.
public class Delayer
{
public async Task Execute(Func<Task> action) // or public async void Execute(Func<Task> action) if you insist on it.
{
try
{
await Task.Delay(10).ConfigureAwait(false);
await action.Invoke();
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
you can then safely do
void CallDelayedMethod()
{
var delayer = new Delayer();
delayer.Execute(ThrowException);
}
public Task ThrowException()
{
throw new Exception();
}
I would still return a Task and leave it to the caller to ignore it by not awaiting it (fire and forget) or not.
Original answer
You are not following the best practices by using an async void signature in the class Delayer.
public async void Execute(Action action)
should be
public async Task Execute(Action action)
so you can await the call to Execute. Otherwise it is just a fire and forget operation and that makes catching exceptions difficult. By making it awaitbale you can do:
try
{
await Delayer.Execute(...);
}
catch(Exception ex)
{
....
}
From the best practices:
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
Also, you should have Execute accept a Task if you want to pass awaitable actions to it:
public async Task Execute(Func<Task> action)
{
await Task.Delay(10).ConfigureAwait(false);
await action.Invoke();
}

Convert void into async return in C#

I read that returning void from a C# async call is not good. But I have the following scenario:
public async void MainFunction()
{
await DoSomething()
await DoSomethingMore()
}
public void DoSomething()
{
//some code that I want to execute (fire and forget)
}
public void DoSomethingMore()
{
//some code that I want to execute (fire and forget)
}
Since I just want that function be executed with no return at all. Should i keep it like this, or should I return Task from DoSomething()? If I change it to return Task, since my code doesn't need to return anything at all, what should I return?
If i change it to return Task, since my code need return nothing at
all, what should i return?
Your current code wouldn't compile, as you can't await on a void returning method (because it doesn't return an awaitable, which is a type which exposes a GetAwaiter method).
Any void method in the synchronous world should return a Task in the asynchronous world. This allows for anyone who wishes to asynchronously wait on the async operation, and also gets a chance to handle exceptions properly. using async void means that the exception will either be swallowed, or if set to in the configuration, will be rethrown on an arbitrary threadpool thread. Async should be propagated properly all the way.
Note that when you await both operations in MainFunctionAsync, you're not firing and forgetting, you're asynchronously waiting for each of them to complete, sequentially.
public async Task MainFunctionAsync()
{
await DoSomethingAsync();
await DoSomethingMoreAsync();
}
public Task DoSomethingAsync()
{
// Do meaningful async stuff
}
public Task DoSomethingMoreAsync()
{
// Do more meaningful async stuff
}
you can return either of these
Task.FromCompleted;
Task.FromException(ex);
so your method would be like this:
public void MainFunction()
{
await DoSomething()
await DoSomethingMore()
}
public Task DoSomething()
{
try{
//some code that I want to execute (fire and forget)
return Task.FromCompleted;
}
catch(Exception ex){
return Task.FromException(ex);
}
}
//some code that I want to execute (fire and forget)
}
public Task DoSomethingMore()
{
try{
//some code that I want to execute (fire and forget)
return Task.FromCompleted;
}
catch(Exception ex){
return Task.FromException(ex);
}
}

Type 'T' is not awaitable

i am creating a task scheduler so i am trying to make some kind of repeating function that accepts Task and awaits it but i get a strange Exception of Type 'T' is not awaitable
public static Task<T> Interval<T>(TimeSpan pollInterval, Func<T> action, CancellationToken token)
{
return Task.Factory.StartNew(
async () =>
{
for (; ; )
{
if (token.WaitCancellationRequested(pollInterval))
break;
await action();
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
So can anyone tell me how could i await a that generic Task cuz i want the function to accept any Task, Task, bool or any other type ?
You don't need to start a long running task for this - just make your method asynchronous directly:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(true)
{
await Task.Delay(pollInterval, token);
action();
}
}
This will cause the Action to run on the current context. If that is not required, you can use:
await Task.Delay(pollInterval, token).ConfigureAwait(false);
action();
This will cause the Action to not run on the same synchronization context of the caller, and potentially use a ThreadPool thread.
Edit in response to comments:
If you don't want the resulting task to come back canceled, but just return when the token is fired, you could use:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
action();
}
catch(OperationCanceledException e)
{
// Swallow cancellation - dangerous if action() throws this, though....
break;
}
}
}
Edit 2:
If you want to pass in async lambdas, you should make the method take an Func<Task>, not Action:
public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Func<Task> actionTask, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
await actionTask();
}
}
Edit in response to chat:
If you want to poll, but use the results of an operation, you could use:
public static async Task RunAtIntervalAsync<T>(TimeSpan pollInterval, Func<Task<T>> fetchOperation, Action<T> operationOnResult, CancellationToken token)
{
while(!token.IsCancellationRequested)
{
try
{
await Task.Delay(pollInterval, token);
}
catch(OperationCanceledException e)
{
// Swallow cancellation
break;
}
// Get a value
T value = await fetchOperation();
// Use result (ie: update UI)
operationOnResult(value);
}
}
You could then call this via:
RunAtIntervalAsync(TimeSpan.FromSeconds(1),
async () => { await Task.Delay(1000); return "Foo"; },
result => UpdateUI(result),
token);
You can't.
You can make a function that takes a generic asynchronous function – a function that returns a Task<T>.
That would be a Func<Task<T>>.
You can also make a function that takes a generic synchronous function, which is what you have now.
You can't make a single function that can take either, but you can make two overloads.
On an unrelated note, your function never actually uses the return value of the function.
Therefore, you shouldn't make it generic at all; you should instead take a Func<Task> or an Action.
Check an example here post.
Agree with SLaks, you need to make the generic parameter T of Func awaitable in order to use the await.
For example if T is a string the code would "await" for a function that returns just a string.
The await is valid only for Tasks. For more info check this explanation MSDN Blog; the example is in VB.net.

Categories

Resources