Низкая производительность на TaskCanceledException - PullRequest
0 голосов
/ 26 марта 2019

Мне нужно выполнить много (10-100k) операций преобразования параллельно.В этом случае я использую tasks, SymaphoreSlim для управления степенью параллелизма и CancellationTokenSource, чтобы не запускать задачи при возникновении исключения.Я пытаюсь сделать что-то вроде этого:

        var tasks = table.Body.Select(async row =>
        {
            await _semaphore.WaitAsync(_cts.Token).ConfigureAwait(false);
            try
            {
                await Convert(row, preparedData, table, mapper).ConfigureAwait(false);
            }
            catch (Exception)
            {

                _cts.Cancel();
                throw;
            }
        });

        await Task.WhenAll(tasks).ConfigureAwait(false);

Но производительность ужасна.Если я избавлюсь от использования токенов, это займет всего несколько секунд.

        var tasks = table.Body.Select(async row =>
        {
            if (_canceled)
                return;

            await _semaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                await Convert(row, preparedData, table, mapper).ConfigureAwait(false);
            }
            catch (Exception)
            {
                _canceled = true;
                throw;
            }
        });

        await Task.WhenAll(tasks).ConfigureAwait(false);

Есть ли способ использовать CancellationToken s с обычной производительностью?

1 Ответ

0 голосов
/ 02 апреля 2019

Когда ваш код делает _semaphore.WaitAsync(_cts.Token), семафор должен установить отменяемое ожидание; это означает, что он должен зарегистрироваться с токеном отмены и, когда ему будет дан сигнал, удалить ожидание из очереди ожидания. Так что да, я ожидаю проблем с производительностью при 100 000 регистраций.

Если вам не нужно , нужно отменить ожидание, я бы не стал.

await _semaphore.WaitAsync().ConfigureAwait(false);
_cts.Token.ThrowIfCancellationRequested();
...