鉴于以下代码,为什么ask.WhenAny
永远不会返回时提供Task.Delay
1秒?从技术上讲,我不确定它是否会在较长时间后返回,但在 15 秒左右之后它不会返回,之后我手动终止该进程。根据文档,我不需要手动启动delayTask
,事实上,如果我尝试手动执行此操作,我会收到异常。
当用户在 WPF 应用程序中选择上下文菜单项时,将从 UI 线程调用该代码,但如果我为上下文菜单项指定了单击方法,并在新线程中运行此代码,则该代码可以正常工作。
public void ContextMenuItem_Click(object sender, RoutedEventArgs e)
{
...
SomeMethod();
...
}
public void SomeMethod()
{
...
SomeOtherMethod();
....
}
public void SomeOtherMethod()
{
...
TcpClient client = Connect().Result;
...
}
//In case you're wondering about the override below, these methods are in
//different classes i've just simplified things here a bit so I'm not posting
//pages worth of code.
public override async Task<TcpClient> Connect()
{
...
Task connectTask = tcpClient.ConnectAsync(URI.Host, URI.Port);
Task delayTask = Task.Delay(1000);
if (await Task.WhenAny(connectTask, delayTask) == connectTask)
{
Console.Write("Connected\n");
...
return tcpClient;
}
Console.Write("Timed out\n");
...
return null;
}
如果我将 ContextMenuItem_Click 更改为以下内容,则效果很好
public void ContextMenuItem_Click(object sender, RoutedEventArgs e)
{
...
new Thread(() => SomeMethod()).Start();
...
}
我预测在你的调用堆栈中,你会调用Task.Wait
or Task<T>.Result
。这会造成僵局我在我的博客上详细解释了这一点。
简而言之,发生的事情是await
将(默认情况下)捕获当前“上下文”并使用它来恢复其async
方法。在此示例中,“上下文”是 WPF UI 上下文。
所以,当你的代码执行它的操作时await
关于返回的任务WhenAll
,它捕获 WPF UI 上下文。稍后,当该任务完成时,它将尝试在 UI 线程上恢复。但是,如果 UI 线程被阻塞(即,在调用Wait
or Result
),那么async
方法无法继续运行,并且永远不会完成它返回的任务。
正确的解决方案是使用await
代替Wait
or Result
。这意味着您的调用代码需要是async
,它将通过您的代码库传播。最终,您需要决定如何使 UI 异步,这本身就是一门艺术。至少一开始,你需要一个async void
事件处理程序或某种异步 MVVM 命令(我探索MSDN 文章中的异步 MVVM 命令)。从那里你需要设计一个合适的异步 UI;即,当异步操作正在进行时,您的 UI 的外观以及它允许执行哪些操作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)