Перейти к содержанию

SemaphoreSlim

SemaphoreSlim — примитив синхронизации, аналогичный Semaphore, но более легковесный, и не использующий примитивы операционной системы. Из-за этого он рекомендуется для синхронизации потоков в одном приложении.
При создании семафора указывается, сколько потоков могут одновременно зайти в критическую секцию. При этом существует конструктор с двумя параметрами — начальным и максимальным числом допустимых потоков. Вызов метода Wait или WaitAsync уменьшает счётчик допустимых потоков, а Release — увеличивает. При этом существует перегрузка Release с параметром, указывающим, насколько увеличить счётчик. Это можно использовать, к примеру, для того, чтобы сперва создать ожидающие таски, и только потом их запустить, вызвав Release с необходимым значением счётчика потоков.

Пример использования

Пусть мы хотим выполнить несколько тасок над коллекцией однотипных данных. Первое, что приходит на ум:

public async Task ProcessManyItems(List<string> items)
{
  var tasks = items.Select(
    async item => await ProcessItem(item));
  await Task.WhenAll(tasks);
}

Однако, в случае достаточно большого числа элементов будет создано слишком много потоков. Мы хотим ограничить параллелизм, это можно сделать (помимо других вариантов), используя SemaphoreSlim для контроля за числом потоков, одновременно входящих в критическую секцию:
public async Task ProcessManyItems( List<string> items,  int maxConcurrency = 10)
{
  using (var semaphore = new SemaphoreSlim(maxConcurrency))
  {
    var tasks = items.Select(async item =>
     {
       // Таск завершается, когда есть свободное место
       await semaphore.WaitAsync(); 
       try
       {
         await ProcessItem(item);
       }
       finally
       {
         semaphore.Release();
       }
     });
     await Task.WhenAll(tasks);
  }
}

Ссылки

Документация
Статья с примером


Последнее обновление : 12 июня 2023 г.
Дата создания : 12 июня 2023 г.

Комментарии

Комментарии