0

以下是 Microsoft在 ASP.NET Core SignalR中使用流式传输一文的摘录:

private async Task WriteItemsAsync(
    ChannelWriter<int> writer,
    int count,
    int delay,
    CancellationToken cancellationToken)
{
    try
    {
        for (var i = 0; i < count; i++)
        {
            // Check the cancellation token regularly so that the server will stop
            // producing items if the client disconnects.
            cancellationToken.ThrowIfCancellationRequested();
            await writer.WriteAsync(i);

            // Use the cancellationToken in other APIs that accept cancellation
            // tokens so the cancellation can flow down to them.
            await Task.Delay(delay, cancellationToken);
        }
    }
    catch (Exception ex)
    {
        writer.TryComplete(ex);
    }

    writer.TryComplete();
}

如果有异常,它会先调用 writer.TryComplete(ex),然后调用 writer.TryComplete()。换句话说,它两次调用 TryComplete(尽管重载不同)。

这是必要的吗?我应该在 writer.TryComplete(ex) 之后添加一个 return 语句以避免调用它两次吗?或者第二个 writer.TryComplete() 在调用前者之后是否有一些有意义的目的?

4

1 回答 1

1

这不是必需的。这不是频道制作人的最佳示例。writer.TryComplete()应该是try{}块的最后一次调用:

private async Task WriteItemsAsync(
    ChannelWriter<int> writer,
    int count,
    int delay,
    CancellationToken cancellationToken)
{
    try
    {
        for (var i = 0; i < count; i++)
        {
            // Check the cancellation token regularly so that the server will stop
            // producing items if the client disconnects.
            cancellationToken.ThrowIfCancellationRequested();
            await writer.WriteAsync(i);

            // Use the cancellationToken in other APIs that accept cancellation
            // tokens so the cancellation can flow down to them.
            await Task.Delay(delay, cancellationToken);
        }
        writer.TryComplete();
    }
    catch (Exception ex)
    {
        writer.TryComplete(ex);
    }   
}

这样,它只被调用一次,无论是在循环成功终止时,还是在由于任何原因引发异常时。

ThrowIfCancellationRequested您可以简单地跳出循环,而不是取消取消:

for (var i = 0; i < count; i++)
{
    if (cancellationToken.IsCancellationRequested)
    {
        break;
    }
    await writer.WriteAsync(i);
    await Task.Delay(delay, cancellationToken);
}
writer.TryComplete();

在有界通道的情况下,WriteAsync也应该收到取消令牌,否则如果通道已满,可能会卡住:

await writer.WriteAsync(i,cancellationToken);
于 2019-09-06T15:27:31.933 回答