代码之家  ›  专栏  ›  技术社区  ›  Leandro Bardelli

如何锁定平行。每n次迭代,而不是每次?

  •  1
  • Leandro Bardelli  · 技术社区  · 3 年前

    我有以下代码:

    int counter = 1;
    var lockTarget = new object();
    Parallel.For(1, totalSIM,  i => {
    
        /* do some stuff  */
    
        lock(lockTarget) {
            _printConcurrent(counter++);
        }
    
    }); 
    

    我需要打电话 _printConcurrent 每隔约200次,而不是每次。我想做一个 MOD (%)的 counter ,但我不明白如何使用这个条件。我随信附上 lock 在if中,但我不能使用 柜台 所以我在一个逻辑循环中,而不是代码:S

    如有任何帮助,我们将不胜感激。

    _打印并发 只是过程的输出,我牺牲了一些性能来监视数据。

    1 回复  |  直到 3 年前
        1
  •  2
  •   Theodor Zoulias    3 年前

    您可以原子级地递增 counter 不锁定,带有 Interlocked.Increment 方法,然后输入 lock 仅当原子增量的结果可被200整除时:

    int counter = 0;
    ParallelOptions options = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
    Parallel.For(0, totalSIM, options, i => {
    
        /* do some stuff */
    
        int current = Interlocked.Increment(ref counter);
        if (current % 200 == 0)
        {
            lock (options) _printConcurrent(current);
        }
    
    });
    

    通过这种方式 _printConcurrent 将每200次迭代调用一次,而不阻塞其余199次迭代。


    更新: 上述方法有一个小缺陷。它不能保证 _打印并发 将以递增的参数顺序调用。例如,理论上可能 _printConcurrent(400) 将在之前调用 _printConcurrent(200) 。这是因为操作系统可以在任何时间挂起任何线程,持续时间约为10-30毫秒( demo ),因此线程可以在 联锁。定期的加薪 排队,并输掉了进入的比赛 通过非挂起的线程。如果这是一个问题,可以通过在混合中抛出第二个计数器来解决,该计数器仅在 :

    int counter1 = 0;
    int counter2 = 0;
    const int step = 200;
    ParallelOptions options = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
    Parallel.For(0, totalSIM, options, i => {
    
        /* do some stuff */
    
        if (Interlocked.Increment(ref counter1) % step == 0)
        {
            lock (options) _printConcurrent(counter2 += step);
        }
    
    });
    
        2
  •  1
  •   Enigmativity    3 年前

    我确实喜欢Rx或 System.Reactive 这样做的方法。它相当整洁。

    Observable
        .Range(0, totalSIM)
        .Select(x => Observable.Start(() => { /* do stuff */ }))
        .Merge(Environment.ProcessorCount)
        .Select((_, n) => n + 1)
        .Where(x => x % 200 == 0)
        .Subscribe(n => _printConcurrent(n));
    
    推荐文章