C # TPL Перечислители с несколькими списками Один модификатор без голодания - PullRequest
1 голос
/ 01 декабря 2010

У меня есть несколько потоков, созданных с помощью TPL (вероятно, не актуально). Некоторые потоки взаимодействуют с конкретным объектом, просто перечисляя содержащийся список без каких-либо изменений. Другие темы добавляют или удаляют элементы из списка. В настоящее время у меня есть оператор блокировки вокруг всех сегментов кода, которые перечисляют список, и операторы блокировки вокруг всех сегментов кода, которые изменяют список.

У меня нет проблем с производительностью, вот и все. Тем не менее, я понимаю, что более эффективным решением было бы позволить многим параллельным перечислителям и блокировать все остальное при изменении списка. В настоящее время только один поток может перечислять список в любой момент времени. Для дальнейшего использования, какой шаблон это позволяет?

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

Enumerate 1
Enumerate 2 Concurrent with 1
Modify 1 Request is Queued
Enumerate 3 Request is Queued because of Modify Request
Enumerate 4 Request is Queued
Modify 2 Request is Queued
Enumerate 2 Finishes
Enumerate 1 Finishes
Modify 1 Starts because all in-progress at time of request Enumerators Finished
Modify 1 Finishes
Enumerate 3 Starts because Queued Modify 1 Finished
Enumerate 4 Starts
Enumerate 3 Finishes
Enumerate 4 Finishes
Modify 2 Starts
...

Ответы [ 2 ]

2 голосов
/ 03 декабря 2010

Классическим решением проблемы являются блокировки чтения-записи.С блокировками «читатель-писатель» читатели не мешают другим читателям захватить блокировку, но писатели блокируют читателей и других писателей, чтобы они могли безопасно вносить изменения.

Если вы используете TPL, то вы навернякаиметь доступ к System.Threading.ReaderWriterLockSlim .Возьмите блокировку читателя при перечислении списка и снимите блокировку писателя при добавлении или удалении элементов из списка.Это даст вам «следующий уровень» масштабируемости в списке.

2 голосов
/ 01 декабря 2010

Недавно мне пришлось реализовать параллельный список, и вы можете попробовать его, если это поможет:

public class ConcurrentList<T> : IList<T>, IList
{
    private readonly List<T> underlyingList = new List<T>();
    private readonly object syncRoot = new object();
    private readonly ConcurrentQueue<T> underlyingQueue;
    private bool requiresSync;
    private bool isDirty;

    public ConcurrentList()
    {
        underlyingQueue = new ConcurrentQueue<T>();
    }

    public ConcurrentList(IEnumerable<T> items)
    {
        underlyingQueue = new ConcurrentQueue<T>(items);
    }

    private void UpdateLists()
    {
        if (!isDirty)
            return;
        lock (syncRoot)
        {
            requiresSync = true;
            T temp;
            while (underlyingQueue.TryDequeue(out temp))
                underlyingList.Add(temp);
            requiresSync = false;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.ToList().GetEnumerator();
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(T item)
    {
        if (requiresSync)
            lock (syncRoot)
                underlyingQueue.Enqueue(item);
        else
            underlyingQueue.Enqueue(item);
        isDirty = true;
    }

    public int Add(object value)
    {
        if (requiresSync)
            lock (syncRoot)
                underlyingQueue.Enqueue((T)value);
        else
            underlyingQueue.Enqueue((T)value);
        isDirty = true;
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.IndexOf((T)value);
        }
    }

    public bool Contains(object value)
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.Contains((T)value);
        }
    }

    public int IndexOf(object value)
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.IndexOf((T)value);
        }
    }

    public void Insert(int index, object value)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.Insert(index, (T)value);
        }
    }

    public void Remove(object value)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.Remove((T)value);
        }
    }

    public void RemoveAt(int index)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.RemoveAt(index);
        }
    }

    T IList<T>.this[int index]
    {
        get
        {
            lock (syncRoot)
            {
                UpdateLists();
                return underlyingList[index];
            }
        }
        set
        {
            lock (syncRoot)
            {
                UpdateLists();
                underlyingList[index] = value;
            }
        }
    }

    object IList.this[int index]
    {
        get { return ((IList<T>)this)[index]; }
        set { ((IList<T>)this)[index] = (T)value; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool IsFixedSize
    {
        get { return false; }
    }

    public void Clear()
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.Clear();
        }
    }

    public bool Contains(T item)
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.Contains(item);
        }
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.CopyTo(array, arrayIndex);
        }
    }

    public bool Remove(T item)
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.Remove(item);
        }
    }

    public void CopyTo(Array array, int index)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.CopyTo((T[])array, index);
        }
    }

    public int Count
    {
        get
        {
            lock (syncRoot)
            {
                UpdateLists();
                return underlyingList.Count;
            }
        }
    }

    public object SyncRoot
    {
        get { return syncRoot; }
    }

    public bool IsSynchronized
    {
        get { return true; }
    }

    public int IndexOf(T item)
    {
        lock (syncRoot)
        {
            UpdateLists();
            return underlyingList.IndexOf(item);
        }
    }

    public void Insert(int index, T item)
    {
        lock (syncRoot)
        {
            UpdateLists();
            underlyingList.Insert(index, item);
        }
    }
}
...