11

.NET 4.5 和 Async CTP 4.0 中包含await的流程可能由于各种原因而卡住,例如远程客户端没有响应。当然,WaitForAny,当我们也等待一些超时任务时,显然是恢复高层流的一个解决方案。尽管如此,这并不能解决所有可能的问题。

我有以下问题:

  1. 永远不会返回的等待上下文会发生什么?我知道这会造成内存泄漏。我对吗?

  2. 如何在调试器中或使用相应的 API 检查应用程序中存在多少悬空的“等待者”?

  3. 是否可以在全球范围内枚举它们?

  4. 如果 3. 正确,是否可以强制取消这些*await *s 的任务(即清理)?

注意:在问题 4 中,我没有询问在显式任务创建期间要使用的取消项目。我的意思是间接创建任务的情况:

async Task<bool> SomeTask()
{
   await Something();
   ...
   return true;
}

这个问题的动机:

  1. 试图避免内存泄漏
  2. 试图在涉及取消令牌的情况下使代码复杂化
  3. 在许多情况下,每个低级任务的超时时间是事先不知道的,但高级流程可以使用刚刚恢复的方法:“我们被卡住了?没关系,只需清理并让我们重新开始”。
4

2 回答 2

9

1 永远不会返回的等待上下文会发生什么?

我相信它会导致内存泄漏(如果您正在await执行 I/O 操作)。最好总是完成你Task的 s(这意味着总是让你的async方法迟早返回)。

svick 评论的更新:在某些情况下,这不会导致内存泄漏。

2 如何在调试器中或使用相应的 API 检查应用程序中有多少悬空的“等待者”?

我不确定是否有一种简单的方法可以做到这一点。我相信应该可以编写一个调试器插件,使用 SoS 来查找与编译器生成的异步状态机模式匹配的现有堆对象。

但这是很多工作却收效甚微。

3 是否可以在全球范围内枚举它们?

不是使用普通的 API。

如果 3 是正确的,是否可以强制取消这些等待的任务(即清理)?

即使您可以在运行时枚举它们(例如,通过分析 API),您也不能“强制”取消任务。取消是合作的。


处理此问题的正确方法是使用标准取消。基于任务的异步模式文档指定了可取消async方法的指南。

在最低级别:asyncBCL 中的许多 API 采用可选的CancellationToken.

中级:通常让一个async方法接受一个可选项CancellationToken,然后将其传递给其他async方法。

在最高级别:很容易创建一个CancellationToken在给定时间后触发的。

于 2012-10-18T13:55:39.800 回答
2

关于问题 2 和 3,我没有真正的答案。

  1. 只要在应用程序终止时CLR处理任务时正确处理任务中使用的资源,我对此表示怀疑。

拥有永远不会返回的任务几乎不是一件好事。为了避免这种情况并回答第 4 点:可以取消任务。

您需要创建一个传递给任务的取消令牌。该任务自己负责监视该取消令牌的状态并在取消时抛出异常。(也可以使用同一个令牌一次取消多个任务。)

MSDN 上的这篇文章向您展示了这样做。

于 2012-10-18T12:07:52.587 回答