gpt4 book ai didi

c# - 异步任务方法 WaitingForActivation

转载 作者:太空狗 更新时间:2023-10-29 22:56:56 34 4
gpt4 key购买 nike

我发现 async 方法有一个非常令人困惑的行为。考虑以下控制台应用程序:

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;
});
}

正如预期的那样,启动后,它首先打印出一堆 0,然后是 ones,twos 等等。

相比之下,请考虑以下 UWP 应用代码段:

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());
}
}

尽管这两者仅在一个小细节上有所不同,但 UWP 片段只是不断打印出 0,if 语句中的任务状态只是保持 Waitingforactivation。此外,可以通过从 CalculateNextAsync 中删除 asyncawait 来解决此问题:

private static Task<int> CalculateNextAsync()
{
return Task.Run(async () =>
{
await Task.Delay(2000);
return ++_i;
});
}

现在一切都与控制台应用程序中的工作方式相同。

有人可以解释控制台中的行为与 UWP 应用不同的原因吗?为什么在 UWP 应用程序中任务保持为 c

更新

我又回到了这个问题,但发现了一个问题,原来接受的答案没有涵盖——UWP 上的代码从未到达.Result,它只是不断检查返回 falseIsCompleted,因此返回 _lastResult。什么使 Task 在本应完成时具有 AwaitingActivation 状态?

解决方案

我发现原因是事件等待 while 循环阻止 await 继续再次占用 UI 线程,因此导致类似“死锁”情况。

最佳答案

根据 UWP 应用程序中的代码,无需保留 _calculateTask。只需等待任务即可。

这是更新后的代码

private static int _i = 0;
private static int _lastResult = 0;

public async Task<int> Calculate() {
_lastResult = await CalculateNextAsync();
return _lastResult;
}

//No need to wrap the code in a Task.Run. Just await the async code
private static async Task<int> CalculateNextAsync()
await Task.Delay(2000);
return ++_i;
}

//Event Handlers allow for async void
private async void Button_Click(object sender, RoutedEventArgs e) {
while( true) {
var result = await Calculate();
Debug.WriteLine(result.ToString());
}
}

原始答案

您在 UWP 应用程序中混合了异步/等待和阻塞调用,例如 .Result,因为它的一个 block SynchronizationContext 而导致死锁。控制台应用程序是该规则的一个异常(exception),这就是它在那里工作而不在 UWP 应用程序中工作的原因。

The root cause of this deadlock is due to the way await handlescontexts. By default, when an incomplete Task is awaited, the current“context” is captured and used to resume the method when the Taskcompletes. This “context” is the current SynchronizationContext unlessit’s null, in which case it’s the current TaskScheduler. GUI andASP.NET applications have a SynchronizationContext that permits onlyone chunk of code to run at a time. When the await completes, itattempts to execute the remainder of the async method within thecaptured context. But that context already has a thread in it, whichis (synchronously) waiting for the async method to complete. They’reeach waiting for the other, causing a deadlock.

Note that console applications don’t cause this deadlock. They have athread pool SynchronizationContext instead of a one-chunk-at-a-timeSynchronizationContext, so when the await completes, it schedules theremainder of the async method on a thread pool thread. The method isable to complete, which completes its returned task, and there’s nodeadlock. This difference in behavior can be confusing whenprogrammers write a test console program, observe the partially asynccode work as expected, and then move the same code into a GUI orASP.NET application, where it deadlocks.

引用 Async/Await - Best Practices in Asynchronous Programming

关于c# - 异步任务方法 WaitingForActivation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46966772/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com