不使用CancellationToken是否可能取消C#任务?

5

我需要取消一个返回Task的API调用,但它没有接受CancellationToken作为参数的方法,也无法添加该参数。

我该如何取消该Task?

在这种情况下,我正在使用带有Geocoder对象的Xamarin.Forms。

 IEnumerable<Position> positions = await geo.GetPositionsForAddressAsync(address); 

有时候,那个调用需要很长时间。对于我的一些使用情况而言,用户可以导航到另一个屏幕,而这个任务的结果就不再需要了。

我也担心我的应用程序会休眠,而这个长时间运行的任务没有停止,或者任务完成并且需要的代码已经无效。


2
假设我们一直在谈论.NET代码,也许你可以将它放入一个子AppDomain中?然后,如果它表现不良或对小猫很残忍,你只需调用Unload()即可。 - user585968
@MickyDuncan 卸载 AppDomain 仍然不是最好的解决方案,如果您使用了非托管资源并且由于卸载而没有被释放,那么它将一直保留,直到所有 AppDomains 都被卸载并且进程终止。更好的方法可能是将其作为完全独立的进程,并使用某种形式的 IPC 与两者通信。 - Scott Chamberlain
@ScottChamberlain 我确实说过“假设我们一直在谈论.NET代码”。是的,我喜欢IPC方法,谢谢Scott。 - user585968
1
@mickyDuncan 我会考虑在.NET代码中执行Marshal.AllocHGlobalMarshal.StructureToPtr,来序列化一个结构体,但我理解你的观点。 - Scott Chamberlain
2个回答

9

我所读到的最好的关于这个的文章来自.NET并行编程博客上的Stephen Toub

基本上,您需要创建自己的取消“重载”:

public static async Task<T> WithCancellation<T>( 
    this Task<T> task, CancellationToken cancellationToken) 
{ 
    var tcs = new TaskCompletionSource<bool>(); 
    using(cancellationToken.Register( 
                s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs)) 
        if (task != await Task.WhenAny(task, tcs.Task)) 
            throw new OperationCanceledException(cancellationToken); 
    return await task; 
}

然后使用try/catch来调用您的异步函数:

try 
{ 
    await op.WithCancellation(token); 
} 
catch(OperationCanceledException) 
{ 
    op.ContinueWith(t => /* handle eventual completion */); 
    … // whatever you want to do in the case of cancellation 
}

真的需要阅读他的博客文章...


4
需要翻译的内容:Just to be clear, that doesn't cancel the task... it cancel's the await on the task, and then you queue up a "cleanup" action, for whenever it does eventually complete. Neat concept, and interesting blog post.为了明确,这并不会取消任务… 它只是取消等待任务完成的操作,然后您可以安排一个“清理”动作,以便在任务最终完成时执行。非常巧妙的概念,有趣的博客文章。 - b0redom
太好了。我可以扩展它以处理超时。我可以在单独的线程中处理任务的实际结束,并且只需丢弃数据。谢谢! - TimF

4
简而言之,如果一个c#任务不尝试观察CancellationToken,那么在你所提到的上下文中,取消它是不可能的。(例如,结束应用程序可以这样做)本Cancellation链接讨论了如何利用取消标记的各种模式,但由于你正在处理一个你无法控制的库,所以你没有太多办法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接