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.Runs 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.