I found a very confusing behavior of async methods. Consider the following console application:
private static int _i = 0; private static Task<int> _calculateTask = Task.FromResult(0); private static int _lastResult = 0; static void Main(string[] args) { while (true) { Console.WriteLine(Calculate()); } } private static int Calculate() { if (!_calculateTask.IsCompleted) { return _lastResult; } _lastResult = _calculateTask.Result; _calculateTask = CalculateNextAsync(); return _lastResult; } private static async Task<int> CalculateNextAsync() { return await Task.Run(() => { Thread.Sleep(2000); return ++_i; }); }
As expected, after starting it first prints a bunch of 0s, then those, two, etc.
In contrast, consider the following fragment of a UWP application:
private static int _i = 0; private static Task<int> _calculateTask = Task.FromResult(0); private static int _lastResult = 0; public int Calculate() { if (!_calculateTask.IsCompleted) { return _lastResult; } _lastResult = _calculateTask.Result; _calculateTask = CalculateNextAsync(); return _lastResult; } private static async Task<int> CalculateNextAsync() { return await Task.Run( async() => { await Task.Delay(2000); return ++_i; }); } private void Button_Click(object sender, RoutedEventArgs e) { while( true) { Debug.WriteLine(Calculate()); } }
Although the two differ in only one small detail, the UWP fragment simply continues to print 0, and the task state in the if simply remains Waitingforactivation . In addition, the problem can be fixed by removing async and await from CalculateNextAsync :
private static Task<int> CalculateNextAsync() { return Task.Run(async () => { await Task.Delay(2000); return ++_i; }); }
Now everything works the same as in the console application.
Can someone explain the reason why the behavior in the Console is different from the UWP application? And why does the task remain as c in the case of a UWP application?
Update
I returned to this question again, but found that the originally accepted answer is not distributed - the UWP code never reaches .Result , it just keeps checking IsCompleted , which returns false , therefore _lastResult returned. What does it mean that Task has an AwaitingActivation state when it should end?
Decision
I found out that the reason is that the active while wait while prevents the continuation of await from ever capturing the UI thread, which leads to a deadlock situation.