如何取消异步调用?

18

如何取消异步调用?.NET APM似乎不支持此操作。

我的代码中有以下循环,它在线程池上生成多个线程。当我在UI上点击一个按钮时,我希望这些线程(或异步调用)结束。

foreach (var sku in skus)
{
    loadSku.BeginInvoke(...
}

除了创建全局的“取消标志”并让异步方法查找它之外,是否还有其他优雅的解决方案?

3个回答

19
一个“取消标志”是实现这一点的方法,虽然不一定是全局的。不可避免的一点是,你需要某种方式向线程发出信号,告诉它应该停止正在做的事情。
BeginInvoke中,除了全局标志以外,很难使用其他任何东西来实现这个目的,因为工作是在线程池上完成的,而你不知道哪个线程在执行。你有几个选项(按优先顺序):
  1. 使用BackgroundWorker替代BeginInvoke。它内置了取消功能。它还有其他好处,如进度监控工作完成回调。它还可以很好地处理异常
  2. 使用ThreadPool.QueueUserWorkItem,将一个对象作为状态传递进去,该对象具有设置Cancelled标志的Cancel()方法,执行代码可以检查该标志。当然,您需要保留对状态对象的引用,以便可以在其上调用Cancel()(这是BackgroundWorker为您完成的——您在表单上有一个组件。感谢Fredrik提醒我们这一点)。
  3. 创建自己的ThreadStart委托,与选项2一样传入状态对象。

+1:关于QUWI的话题,它也更加轻量级,因为如果池没有满的话,就不需要创建线程。 - Steven Evers
如果您复制了别人的答案,而没有进行引用,那么请给自己打上-1。如果您提供更清晰和额外的信息,请点赞。 http://social.msdn.microsoft.com/Forums/en-US/4de6dd12-cf9b-427b-bd30-7a26c3e86bc2/how-to-cancel-asynchronous-method-execution?forum=netfxbcl - electricalbah
1
@electricalbah 请检查日期。这篇文章是2009年的原始文章,而不是你引用的2012年MSDN文章。在这种情况下应该是他们引用。但既然这是互联网,所以担心也没有意义。可惜你在未核实事实的情况下进行了负评。 - Neil Barnwell
@NeilBarnwell 我明白了,很抱歉。我确实检查了日期,但是把日子误认为是年份了。我会为我的愚蠢进行补偿。 - electricalbah
1
@electricalbah 一个简单的错误。我很惊讶自己被引用了,但并非逐字逐句。有人花时间剪切我的帖子,并用其中的内容写了自己的帖子。奇怪的现象。 - Neil Barnwell
显示剩余2条评论

1
如果你正在寻找一个“TerminateAsnyc”方法,那么你不会找到它。因此,在使用Control.BeginInvoke/EndInvoke时,可能没有一种优雅的方式。因此,我会在UI线程上放置布尔标志,并异步执行检查该标志的委托,以便在执行期间定期检查该标志。

但是,你可以尝试使用后台工作线程。


0

肯定有其他解决方案,尽管我不知道是否应该称它们为“优雅”。

您可以在线程上调用Abort或Interrupt,但这些可能会产生一些负面影响。就个人而言,对于这样的问题,如果可能的话,我更喜欢使用BackgroundWorker。它具有取消功能,但类似于您提到的 - 在执行代码中必须定期检查的类中的bool标志(至少不是全局标志)。.NET中停止线程的此帖子有点旧,但概述了我上面提到的其他选项的一些缺点。


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