如何在Parallel.For循环中终止并获取首个匹配条件的最小迭代索引?
如何在Parallel.For中获取已排序列表的首个匹配索引并终止循环
你的核心问题在于并行迭代时,多线程可能先匹配到较大的索引并触发停止,但此时更小的索引线程可能还在执行,而且state.Stop()无法立刻终止所有正在运行的线程,也无法保证只保留最小的匹配索引。以下是针对性的解决方案:
解决思路
- 使用线程安全的变量存储最小匹配索引,避免多线程竞争导致的错误更新。
- 每个线程执行匹配前,先检查是否已找到更小的匹配索引,若已找到则直接跳过当前迭代,减少无用计算。
- 用
state.Break()替代state.Stop():Break()会通知循环停止处理大于当前索引的后续迭代,确保所有更小索引的迭代都能被处理,不会漏掉首个匹配项。 - 统一在循环结束后输出结果,避免多线程同时输出多个索引。
修改后的代码
// 初始化最小匹配索引为最大值,代表未找到匹配 int foundIndex = int.MaxValue; Parallel.For(0, patterns.Count, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (int i, ParallelLoopState state) => { // 读取当前已找到的最小索引(Volatile.Read保证获取最新值) int currentFound = Volatile.Read(ref foundIndex); // 如果已找到比当前i更小的匹配,直接跳过并终止后续大索引迭代 if (currentFound < i) { state.Break(); return; } bool match = MyMatcher(myPattern, patterns[i]); if (match) { // 线程安全地更新最小索引:仅当当前i比已存索引更小时才更新 Interlocked.CompareExchange(ref foundIndex, i, currentFound); // 如果当前i是最新的最小索引,触发Break停止后续大索引迭代 if (Volatile.Read(ref foundIndex) == i) { state.Break(); } } }); // 循环结束后输出最终结果 if (foundIndex != int.MaxValue) { Console.WriteLine(foundIndex.ToString()); }
关键细节说明
Volatile.Read:确保线程读取到的foundIndex是内存中的最新值,避免线程缓存旧值导致的判断错误。Interlocked.CompareExchange:原子性地完成“比较-更新”操作,保证多线程环境下只有更小的索引能覆盖已存值。state.Break():区别于Stop()的立即终止所有新迭代,Break()会优先处理完当前索引之前的所有迭代,确保不会漏掉更小的匹配项,完全适配你“已排序列表取首个匹配”的需求。
内容的提问来源于stack exchange,提问作者Joey
相关产品推荐
相关产品推荐

