正确使用 ConcurrentBag

本文关键字:ConcurrentBag | 更新日期: 2023-09-27 18:22:30

编辑:谢谢,你让我意识到下面的代码没有像我假设的那样工作,因为不知何故我认为cbag就像一个哈希集。对不起,你省去了我一些头痛:)

以下函数是唯一可以更改_currentSetOfStepsProcessing的函数。可以从不同的线程调用此函数。我不确定我是否正确理解了ConcurrentBag的使用,所以请让我知道你认为这是否可以工作。进程启动后,_stepsToDo永远不会修改数据结构。

void OnStepDone(InitialiseNewUserBase obj)
    {
        var stepToDo = _stepsToDo[_currentSetOfStepsProcessing];
        stepToDo.TryTake(out obj);
        if (stepToDo.Count == 0) //can I assume it will enter here once per ConcurrentBag?
        {
            if (_currentSetOfStepsProcessing < _stepsToDo.Count - 1)
            {
                _currentSetOfStepsProcessing++;
            }
        }
    }
    List<ConcurrentBag<InitialiseNewUserBase>>      _stepsToDo = new List<ConcurrentBag<InitialiseNewUserBase>>();
    Action                                          _onFinish;
    int                                             _currentSetOfStepsProcessing;

正确使用 ConcurrentBag

  1. stepToDo.TryTake(out obj);可能会失败,你不会处理它。
  2. 你为什么要out引用方法参数?这只会覆盖参数。如果你把它扔掉,为什么要争论呢?更有可能的是,这是某种误解。
  3. can I assume it will enter here once per ConcurrentBag由于对包的访问显然是并发的,因此多个访问线程可能会看到0。所以是的,你需要更好地处理这种情况。

也许,您不应该让事情变得如此困难,并将lock与非并发数据结构结合使用。只有当袋子操作的频率很高时,这才是一个好主意,这似乎不太可能。

这个呢:

foreach (/*processing step*/) {
 Parallel.ForEach(/*item in the step*/, x => { ... });
}

简单得多。