I have a minimal example of some async code that is exhibiting strange behavior. This is sandbox code, more geared at trying to understand async better --
private async Task ExhibitStrangeBehaviorAsync()
{
async Task TaskA()
{
await Task.Run(async () =>
{
throw new Exception(nameof(TaskA));
await Task.Yield();
});
}
async Task TaskB()
{
await Task.Run(() =>
{
throw new Exception(nameof(TaskB));
});
}
var tasks = new List<Task>
{
TaskA(),
TaskB(),
};
var tasksTask = Task.WhenAll(tasks);
try
{
await tasksTask;
}
catch
{
Debug.WriteLine(tasksTask.Exception.Message);
}
}
Intermittently, this code will hang. I would like to better understand why. My guess currently is the intermittent nature is due to the out-of-order execution of the aggregated tasks, and/or this line from Asynchronous Programming:
Lambda expressions in LINQ use deferred execution, meaning code could end up executing at a time when you're not expecting it to.
TaskA
would fall in this category.
The code does not seem to hang if TaskB
also Task.Run
s an async lambda, or if neither local Task
function contains Task.Run
, e.g.
async Task TaskA()
{
//await Task.Run(async () =>
//{
throw new Exception(nameof(TaskA));
await Task.Yield();
//});
}
async Task TaskB()
{
//await Task.Run(() =>
//{
throw new Exception(nameof(TaskB));
//});
}
Can anybody shed some light on what's going on here?
EDIT
This is executing in the context of a UI thread, specifically that of a Xamarin.Forms application.
EDIT 2
Here is another variant on it that runs straight out of the Xamarin.Forms OnAppearing
lifecycle method. I had to modify TaskA
/B
slightly, though they break this way with the original setup above as well.
protected async override void OnAppearing()
{
base.OnAppearing();
async Task TaskA()
{
await Task.Run(async () =>
{
throw new InvalidOperationException();
await Task.Delay(1).ConfigureAwait(false);
}).ConfigureAwait(false);
}
async Task TaskB()
{
await Task.Run(() => throw new ArgumentException()).ConfigureAwait(false);
}
var tasks = new List<Task>
{
TaskA(),
TaskB(),
};
var tasksTask = Task.WhenAll(tasks);
try
{
await tasksTask;
}
catch
{
Debug.WriteLine(tasksTask.Exception.Message);
}
}
There is some chance this may be related to another issue I have had - I am using an older version of Xamarin.Forms, one which has problems with its OnAppearing
handling async correctly. I am going to try with a newer version to see if it resolves the issue.