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

C#中Parallel.ForEach同名资源互斥执行的解决方案

解决方案:用ConcurrentDictionary结合SemaphoreSlim实现按资源串行、跨资源并行

核心思路是用线程安全的字典维护每个资源对应的信号量,同一资源共享一个初始计数为1的信号量,确保同一时间只有一个线程处理该资源;不同资源的信号量相互独立,实现跨资源并行。

具体代码实现

using System.Collections.Concurrent;
using System.Threading;

string[] arr = ["A", "B", "B", "B", "B", "B", "C"];

var options = new ParallelOptions() { 
    MaxDegreeOfParallelism = 3 
};

// 线程安全字典,存储每个资源对应的信号量
var resourceLocks = new ConcurrentDictionary<string, SemaphoreSlim>();

try
{
    Parallel.ForEach(arr, options, res =>
    {
        // 获取或创建当前资源对应的信号量(初始计数1,最多允许1个线程进入)
        var semaphore = resourceLocks.GetOrAdd(res, _ => new SemaphoreSlim(1, 1));
        
        try
        {
            // 等待信号量,同一资源的线程会在此排队
            semaphore.Wait();
            
            // -------------------------
            // 这里写处理res的业务代码
            Console.WriteLine($"开始处理 {res} | 线程ID: {Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(1000); // 模拟耗时操作
            Console.WriteLine($"完成处理 {res} | 线程ID: {Thread.CurrentThread.ManagedThreadId}");
            // -------------------------
        }
        finally
        {
            // 释放信号量,让下一个等待该资源的线程进入
            semaphore.Release();
        }
    });
}
finally
{
    // 清理所有信号量,避免资源泄漏
    foreach (var kvp in resourceLocks)
    {
        kvp.Value.Dispose();
    }
    resourceLocks.Clear();
}

为什么不用命名信号量?

命名信号量是系统级别的跨进程同步工具,适合多个进程间的资源互斥,但这里只需要进程内的同步,用它反而有以下问题:

  • 需要手动维护唯一命名,容易出现命名冲突;
  • 生命周期管理繁琐,需要手动释放,否则会残留系统资源;
  • 性能比进程内的SemaphoreSlim更重,没必要。

关键逻辑说明

  • ConcurrentDictionary<string, SemaphoreSlim>:线程安全的字典,确保多个线程同时访问同一资源时,只会创建一个信号量实例;
  • SemaphoreSlim(1,1):初始计数为1,最大计数为1,等价于一个排他锁,同一时间只有一个线程能进入临界区;
  • Wait()和Release():Wait()会阻塞当前线程直到信号量可用,处理完成后Release()释放信号量,让下一个等待的线程执行。

这样就能实现:A和B可以同时执行,多个B必须串行执行的需求,完全解决运行时动态创建锁的问题,不需要静态化任何资源。

内容的提问来源于stack exchange,提问作者Sameh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:57:13