You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

受控并行任务执行咨询:并行场景下单任务串行执行同步需求

解决方案:用双重同步机制实现独占串行任务

听起来你现在的场景是:有一批任务用4个并发并行执行,现在要插入一个必须独占执行的任务——这个任务跑的时候,所有并行任务都得停,而且你不能把整个并行逻辑改成同步的。你尝试用Semaphore来等待所有4个并行任务完成,但遇到了问题,对吧?

我之前处理过类似的需求,核心思路是用两个同步对象配合:一个控制并行并发数的Semaphore,再加一个独占锁来保护“抢占所有并行许可”的操作。这样既能保证并行任务正常的4并发,又能让串行任务安全地“暂停”所有并行任务。

具体实现思路

  1. 并行任务控制:用初始许可数为4的Semaphore,每个并行任务执行前获取许可,执行完释放,维持4个并发。
  2. 串行任务独占逻辑
    • 先用一个独占锁(比如Mutex或者单许可Semaphore)确保同一时间只有一个串行任务在尝试“抢占所有并行许可”。
    • 然后逐个获取所有4个并行Semaphore的许可——这一步会自动等待所有正在运行的并行任务执行完毕(因为它们会释放许可),同时阻止新的并行任务启动(因为没有许可可用)。
    • 执行你的串行任务,完成后一次性释放所有4个并行许可,让并行任务恢复正常执行。

代码示例(以C#为例)

// 控制并行任务的并发数,初始4个许可
private static readonly SemaphoreSlim ParallelSemaphore = new SemaphoreSlim(4);
// 独占锁:确保只有一个串行任务在执行"抢占所有并行许可"的流程
private static readonly SemaphoreSlim ExclusiveTaskLock = new SemaphoreSlim(1);

// 并行任务逻辑
async Task ExecuteParallelTask(object taskItem)
{
    // 等待获取并行许可,自动排队等待
    await ParallelSemaphore.WaitAsync();
    try
    {
        // 这里写你的并行任务业务逻辑
        Console.WriteLine($"并行任务执行中:{taskItem}");
        await Task.Delay(1000); // 模拟任务耗时
    }
    finally
    {
        // 必须释放许可,否则会导致死锁
        ParallelSemaphore.Release();
    }
}

// 独占串行任务逻辑
async Task ExecuteExclusiveSerialTask()
{
    // 先获取独占锁,避免多个串行任务同时抢占并行许可
    await ExclusiveTaskLock.WaitAsync();
    try
    {
        // 抢占所有4个并行许可:这一步会等待所有正在运行的并行任务结束
        for (int i = 0; i < 4; i++)
        {
            await ParallelSemaphore.WaitAsync();
        }

        try
        {
            // 此时所有并行任务都处于等待状态,执行你的串行任务
            Console.WriteLine("=== 独占串行任务开始执行,所有并行任务已暂停 ===");
            await Task.Delay(3000); // 模拟串行任务耗时
        }
        finally
        {
            // 释放所有4个并行许可,让并行任务恢复执行
            ParallelSemaphore.Release(4);
            Console.WriteLine("=== 独占串行任务执行完毕,并行任务恢复 ===");
        }
    }
    finally
    {
        // 释放独占锁,让下一个串行任务可以执行
        ExclusiveTaskLock.Release();
    }
}

你之前可能遇到的问题分析

如果你之前只单独用Semaphore尝试等待4个对象,大概率是没处理好这两个关键点:

  • 没有独占锁保护:如果有多个串行任务同时触发,它们会同时去抢并行许可,导致逻辑混乱,甚至死锁。
  • 没有完整抢占所有许可:如果只抢了部分许可,还有并行任务在运行,就达不到“串行任务执行时其他任务完全等待”的要求。

其他语言的适配思路

如果是Python、Java等语言,逻辑完全一致:

  • Python:用threading.Semaphore(4)控制并行,threading.Lock()作为独占锁,串行任务先acquire锁,然后acquire并行Semaphore 4次,执行后release 4次,再release锁。
  • Java:用Semaphore(4)控制并行,ReentrantLock作为独占锁,逻辑和C#一致。

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

火山引擎 最新活动