You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 09:57:45