Bad SemaphoreSlim производительность, используя много семафоров - PullRequest
0 голосов
/ 29 января 2020

Когда я выполняю много операций параллельно, используя SemaphoreSlim для каждого, их вызовы выполняются не так быстро, как ожидалось.

Вот код

  var sw = new Stopwatch();
  sw.Start();

  for (int i = 0; i < 50; i++) {
    int localI = i;
    Task.Run(async () => {
       var semaphore = new SemaphoreSlim(1, 1);
       await semaphore.WaitAsync();
       Thread.Sleep(1000);
       counter++;
       semaphore.Release();
       Debug.WriteLine($"{localI} - {sw.ElapsedMilliseconds}");
     });
  }

  Thread.Sleep(5000);

А вот вывод:

2 - 1015
0 - 1015
1 - 1015
3 - 2053
4 - 2053
5 - 2053
6 - 2120
7 - 3009
8 - 3064
9 - 3066
10 - 3068
11 - 3134
12 - 4011
13 - 4016
14 - 4070
15 - 4071
16 - 4073
17 - 4140

Может кто-нибудь объяснить, почему они не были вызваны примерно через 1 секунду?

1 Ответ

2 голосов
/ 29 января 2020

То, что вы видите, это ограниченная скорость ввода пула потоков. Это не имеет ничего общего с SemaphoreSlim или даже async, так как весь размещенный код на самом деле является синхронным.

На вашей машине три потока могут работать сразу. Пул потоков видит, что у него есть другая работа (47 других элементов уже поставлены в очередь). Таким образом, он ждет немного, а затем вводит другой поток. Следующая группа работ использует четыре потока. Пул потоков все еще находится "позади", поэтому он ждет немного, а затем вводит другой поток и т. Д. c.

Часть "ожидания для бита" в приведенном выше описании - это внедрение ограниченного пула потоков. ставка. Пул потоков должен немного подождать, иначе, когда он получит больше работы, он немедленно создаст группу потоков, которые затем будут удалены, когда работа будет завершена. Таким образом, чтобы быть более эффективным и не допустить такого «перебивания потоков», пул потоков немного подождет, прежде чем создавать новые потоки.

...