如何在Task内的Parallel.ForEach中提前终止执行?
如何在VB.NET的Parallel.ForEach中提前终止循环
首先,你的代码目前有两个关键问题需要解决:一是多线程下计数的线程安全问题,二是没有利用Parallel.ForEach自带的终止机制。下面一步步帮你修改实现需求:
1. 修复线程安全的计数问题
直接对totalCount进行+=1操作在多线程环境下是非原子性的,会导致计数不准确。我们需要用System.Threading.Interlocked.Increment来保证计数的线程安全:
totalCount = Interlocked.Increment(totalCount)
2. 利用ParallelLoopState实现提前终止
Parallel.ForEach的委托可以接收一个ParallelLoopState参数,通过它的方法来终止循环:
Stop():会立即停止所有尚未启动的迭代,尽可能快地终止整个循环(完全匹配你的场景,只要计数达标就不需要继续处理任何新项)Break():会让当前正在执行的迭代完成,并且不再处理索引大于当前迭代的项(更适合按顺序处理的场景)
修改后的完整代码
Dim opt As System.Threading.Tasks.ParallelOptions = New System.Threading.Tasks.ParallelOptions With { .MaxDegreeOfParallelism = My.Settings.ssUserMaxThreads} Dim ttask = Task.Factory.StartNew(Sub() Parallel.ForEach(filesList, opt, Sub(rom As String, loopState As ParallelLoopState) ' 先检查循环是否已终止,避免无效处理 If loopState.IsStopped Then Return End If ProcessROM(rom, romDS, ClassHash) ' 线程安全地递增计数 totalCount = Interlocked.Increment(totalCount) Debug.WriteLine("TotalCount: " & totalCount) If totalCount > LimitedNumber Then Debug.WriteLine("Limited number exceeded") ' 终止Parallel.ForEach循环 loopState.Stop() ' 退出当前委托,不再执行后续UI操作 Return End If con.Invoke(CType(Sub() ReportProgress() End Sub, Action)) End Sub ) End Sub) ' 等待任务完成(替代原来的Do Until循环,若需保持UI响应可改用Async/Await) ttask.Wait()
额外说明
- 移除了
Application.DoEvents():后台线程调用它没有意义,UI线程的消息循环应由UI线程自行处理,后台线程只需通过Invoke更新UI即可。 - 加入
loopState.IsStopped检查:在处理每个ROM前先判断循环是否已终止,避免做无用的ProcessROM调用。 - 若你需要异步等待而不阻塞UI,可以将外层方法改为
Async,然后用Await ttask替代ttask.Wait()。
内容的提问来源于stack exchange,提问作者stigzler
相关产品推荐
相关产品推荐

