C# TaskCanceledException上的低性能

C# TaskCanceledException上的低性能,c#,async-await,task,cancellation,cancellationtokensource,C#,Async Await,Task,Cancellation,Cancellationtokensource,我需要并行运行许多(10-100k)转换操作。在这种情况下,我使用tasks,symaphoresim来控制并行度,并使用CancellationTokenSource来防止在引发异常时不运行要运行的任务。 我正在尝试这样做: var tasks = table.Body.Select(async row => { await _semaphore.WaitAsync(_cts.Token).ConfigureAwait(false)

我需要并行运行许多(10-100k)转换操作。在这种情况下,我使用
tasks
symaphoresim
来控制并行度,并使用
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来实现常规性能?

当您的代码执行
\u信号量.WaitAsync(\u cts.Token)
时,信号量必须设置可取消的等待;这意味着它必须注册取消令牌,当发出信号时,将等待从等待队列中移除。因此,是的,我预计10万注册会出现性能问题

如果你不需要取消等待,我不会

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

Convert
引发异常有多常见?如果没有抛出异常,我希望这两个具有相似的性能。毕竟,
WaitAsync()
只调用
WaitAsync(Timeout.Infinite,default(CancellationToken))
WaitAsync
还有一个快捷方式,
CancellationToken
已经被取消。什么数据类型是
?您能否向我们展示
Convert
的功能?另外,在您的第二个示例中,在获取信号量之前,在方法的最顶端检查
\u cancelled
。因此,我希望每行的
Select
调用在任何一行都有机会获得调用锁
Convert
之前检查
\u cancelled
,因此我认为取消在这里不可能起作用,正如您所描述的那样。@AndreyAlonzov
Convert
做什么?为什么不使用专门为数据并行而构建的
Parallel.ForEach
或PLINQ?并行处理是一回事。并发执行有些非常不同。@AndreyAlonzov您还没有发布关于
Convert
的任何信息。这很重要。如果未向方法传递取消令牌,则无法取消运行
Convert
方法。问题不在于取消令牌
Convert
本身会忽略取消,无论您使用什么库,它都会继续忽略取消。谢谢,@Stephen!即使我试图直接抛出一个异常,也是一样的。在版本构建中,它需要很长的时间(大约是使用布尔标记的10倍),但比调试中快得多。