Параллельное программирование .Net 4.0 - как записать данные в параллельные коллекции? - PullRequest
2 голосов
/ 17 сентября 2010

У меня есть сетка, которая определяется как: List<List<Cell>>, где "Ячейка" - мой пользовательский класс.Моя программа имеет несколько потоков, которые получают доступ к различным координатам в сетке и изменяют данные в классе «Ячейка».Но я хочу, чтобы только один поток записывал данные в объект "Cell" за раз.Я думал, что использование параллельных коллекций, таких как ConcurrentBag, будет полезным, но кажется, что у всех параллельных коллекций есть только методы ДОБАВИТЬ элементы или УДАЛИТЬ их из коллекции.Похоже, не существует поточно-ориентированного способа ИЗМЕНЕНИЯ данных, хранящихся в такой коллекции.

Я что-то здесь упускаю или нет "простого способа" сделать это с помощью таких коллекций?

Ответы [ 3 ]

2 голосов
/ 17 сентября 2010

Вы читали этот документ?

Потоково-безопасные коллекции в .NET Framework 4 и их характеристики производительности

Пример кода с использованием ConcurrentBag:

if (bag.TryTake(out node))
{
    for (int i = 0; i < node.Children.Count; i++)
    {
        bag.Add(node.Children[i]);
    }

    ProcessNode(node); //e.g. a short string comparison
}

Вы также можете взглянуть на Поддержка ConcurrentDictionary для добавления и обновления .

2 голосов
/ 17 сентября 2010

Вы можете просто использовать мьютексы для потокового доступа к содержимому вашей ячейки.Это работает примерно так:

class Cell{

 private static Mutex mut = new Mutex();

    private static void SetResource(...)
    {
        // Wait until it is safe to enter.
        mut.WaitOne();

        //change cell contents here...

        // Release the Mutex.
        mut.ReleaseMutex();
    }

   }

Подробнее см. http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx.

0 голосов
/ 18 сентября 2010

Параллельные коллекции предназначались для безопасного изменения самой коллекции ; не предметы . Вам нужно будет добавить свои собственные примитивы синхронизации в класс Cell. Если внешний и внутренний экземпляры List останутся без изменений, то нет необходимости применять к ним синхронизацию.

Вы упомянули, что у вас будет много читателей, но только один писатель. Это невероятно важная деталь. Это означает, что любые стратегии синхронизации без блокировки становятся значительно проще в реализации. Тем не менее, я не рекомендую идти по этому пути, так как все равно было бы довольно сложно получить права. Но это также может означать, что ReaderWriterLockSlim может работать лучше, чем lock.

Вам придется поэкспериментировать с обоими, чтобы увидеть, какой из них обеспечивает лучший баланс удобства обслуживания и эффективности. Я предполагаю, что вы обнаружите, что традиционный lock будет работать быстрее, несмотря на наличие нескольких читателей и одного писателя, но это стоит проверить. Это, конечно, намного проще при наборе кода.

Вот пример кода для обоих.

public class Cell
{
  private object m_LockObject = new object();

  public object ReadMyState()
  {
    lock (m_LockObject)
    {
      // Return the data here.
    }    
  }

  public void ChangeMyState()
  {
    lock (m_LockObject)
    {
      // Make your changes here.
    }    
  }
}

и

public class Cell
{
  private ReaderWriterLockSlim m_LockObject = new ReaderWriterLockSlim();

  public object ReadMyState()
  {
    m_LockObject.EnterReadLock();
    try
    {
      // Return the data here.
    }
    finally
    {
      m_LockObject.ExitReadLock();
    }
  }

  public void ChangeMyState()
  {
    m_LockObject.EnterWriteLock();
    try
    {
      // Make your changes here.
    }
    finally
    {
      m_LockObject.ExitWriteLock();
    }
  }
}
...