Советы по Оптимизации Производительности
V. Параллелизм и безопасность потоков
Обеспечение потокобезопасности может предотвратить нежелательные ошибки и проблемы с производительностью.
1. По возможности используйте структуры данных без блокировок
Выбор структур данных, таких как ConcurrentBag, ConcurrentQueue или ConcurrentDictionary, может помочь вам обеспечить безопасность потоков в многопоточных сценариях без ущерба для производительности.
Плохо:
private object _sync = new object();
private List<int> _list = new List<int>();
public void Add(int item)
{
lock (_sync)
{
_list.Add(item);
}
}
Здесь используется блокировка для синхронизации доступа к списку, что может привести к конфликтам и снижению производительности.Хорошо:
private ConcurrentBag<int> _bag =
new ConcurrentBag<int>();
public void Add(int item)
{
_bag.Add(item);
}
Используя структуры данных без блокировок, вы можете свести к минимуму конфликты, повысить производительность и обеспечить потокобезопасность в многопоточных сценариях.2. Используйте эффективные конструкции синхронизации
Использование SemaphoreSlim, ReaderWriterLockSlim или Monitor, может помочь вам защитить общие ресурсы и обеспечить безопасность потоков, сводя к минимуму конфликты и влияние на производительность.
Плохо: см. выше.
Хорошо:
private SemaphoreSlim _semaphore
= new SemaphoreSlim(1, 1);
private List<int> _list = new List<int>();
public async Task AddAsync(int item)
{
await _semaphore.WaitAsync();
try
{
_list.Add(item);
}
finally
{
_semaphore.Release();
}
}
Эффективные конструкции синхронизации позволяют защитить общие ресурсы и обеспечить безопасность потоков, сводя к минимуму конфликты и влияние на производительность.3. Используйте Interlocked для атомарных операций
Вы можете выполнять простые атомарные операции, не полагаясь на блокировки, уменьшая конкуренцию и повышая производительность.
Плохо:
private int _counter;
private object _sync = new object();
public void Increment()
{
lock (_syncRoot)
{
_counter++;
}
}
Здесь ключевое слово lock используется для обеспечения потокобезопасности для увеличения счетчика. Однако это может привести к конфликтам и снижению производительности.Хорошо:
private int _counter;
public void Increment ()
{
Interlocked.Increment(ref _counter);
}
Класс Interlocked позволяет выполнять простые атомарные операции без использования блокировок, что повышает производительность и снижает количество конфликтов. Используйте его, когда это возможно, для таких операций, как инкремент, декремент или добавление.Источник: https://dev.to/bytehide/50-c-advanced-optimization-performance-tips-18l2