【发布时间】:2012-05-28 03:02:11
【问题描述】:
所有,这里有一个关于在 C# 中取消 Task:s 的复杂案例的设计/最佳实践的问题。如何实现共享任务的取消?
作为一个最小的例子,让我们假设以下内容;我们有一个长期运行的、可合作取消的操作“工作”。它接受一个取消标记作为参数,如果它被取消则抛出。它对某些应用程序状态进行操作并返回一个值。它的结果是两个 UI 组件独立需要的。
在应用程序状态不变的情况下,应缓存 Work 函数的值,如果正在进行一次计算,则新请求不应开始第二次计算,而是开始等待结果。
任何一个 UI 组件都应该能够取消它的任务,而不会影响其他 UI 组件的任务。
到目前为止,你和我在一起吗?
上述可以通过引入一个Task缓存来完成,该缓存将真正的Work任务包装在TaskCompletionSources中,然后将其Task:s返回给UI组件。如果 UI 组件取消它的任务,它只会放弃 TaskCompletionSource 任务,而不是底层任务。这一切都很好。 UI 组件创建 CancellationSource 和取消请求是一个正常的自上而下的设计,与底部的协作 TaskCompletionSource 任务。
现在,解决真正的问题。应用状态发生变化时怎么办?让我们假设让“工作”函数对状态副本进行操作是不可行的。
一种解决方案是监听任务缓存(或附近)中的状态变化。如果缓存有底层任务使用的 CancellationToken,即运行 Work 函数的任务,它可以取消它。这可能会触发所有附加的 TaskCompletionSources Task:s 的取消,因此两个 UI 组件都将获得 Canceled 任务。这是某种自下而上的取消。
有没有首选的方法来做到这一点?是否有一种设计模式可以在某处描述它?
自下而上的取消是可以实现的,但是感觉有点怪。 UI 任务是使用 CancellationToken 创建的,但由于另一个(内部)CancellationToken 而被取消。此外,由于令牌不相同,因此不能仅在 UI 中忽略 OperationCancelledException - 这将(最终)导致在外部 Task:s 终结器中引发异常。
【问题讨论】:
-
很好的问题,虽然我的第一反应是“tl;dr”
-
所以,澄清一下;您有任务结果的两个消费者,并且您只希望一个任务来计算每个应用程序状态的值;但是您希望每个消费者都能够“取消”等待任务结果吗?
-
是的,但是状态的改变应该取消计算。
标签: c# multithreading cancellation