ChannelReader<T>.ReadAllAsync被 CancellationToken 取消時是否拋出例外?它似乎沒有拋出 OperationCanceledException/TaskCanceledException?
我知道如果這兩種方法被呼叫后就忘記了,也就是說_ = SendLoopAsync(); _ = ReceiveLoopAsync();,它會在沒有顯示訊息/例外的情況下使任務崩潰,因為它們沒有被等待,這意味著我們正在丟失例外。
我不希望它在不讓我知道它實際上已經崩潰/被取消的情況下崩潰該任務,這意味著我可能應該將整個 SendLoopAsync 包裝在 try/catch 中,而不是 ReadAllAsync 分支之間的內容。
一個代表其行為的小例子將不勝感激。
var clientWebSocket = new ClientWebSocket();
await clientWebSocket.ConnectAsync(new Uri("wss://www.deribit.com/ws/api/v2"), CancellationToken.None).ConfigureAwait(false);
var client = new ChannelWebSocket(clientWebSocket);
for (var i = 1; i <= 10; i )
{
client.Output.TryWrite($"Item: {i}");
}
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(1));
await client.StartAsync(cts.Token).ConfigureAwait(false); // blocks the UI
Console.ReadLine();
public class ChannelExample
{
private readonly WebSocket _webSocket;
private readonly Channel<string> _input;
private readonly Channel<string> _output;
public ChannelExample(WebSocket webSocket)
{
_webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
_input = Channel.CreateUnbounded<string>(new UnboundedChannelOptions
{
SingleWriter = true
});
_output = Channel.CreateUnbounded<string>(new UnboundedChannelOptions
{
SingleReader = true
});
}
public ChannelReader<string> Input => _input.Reader;
public ChannelWriter<string> Output => _output.Writer;
public async Task StartAsync(CancellationToken cancellationToken)
{
var receiving = ReceiveLoopAsync(cancellationToken);
var sending = SendLoopAsync(cancellationToken);
var completedTask = await Task.WhenAny(receiving, sending).ConfigureAwait(false);
if (completedTask.Exception != null)
{
Console.WriteLine("Exception");
}
}
private async Task SendLoopAsync(CancellationToken cancellationToken)
{
await foreach (var message in _output.Reader.ReadAllAsync(cancellationToken))
{
Console.WriteLine($"Sending: {message}");
await Task.Delay(5000, cancellationToken).ConfigureAwait(false);
}
}
private async Task ReceiveLoopAsync(CancellationToken cancellationToken)
{
using var buffer = MemoryPool<byte>.Shared.Rent();
while (_webSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
ValueWebSocketReceiveResult receiveResult;
do
{
receiveResult = await _webSocket.ReceiveAsync(buffer.Memory, cancellationToken).ConfigureAwait(false);
if (receiveResult.MessageType == WebSocketMessageType.Close)
{
return;
}
} while (!receiveResult.EndOfMessage);
}
}
}
uj5u.com熱心網友回復:
我懷疑它會拋出;當然,您始終可以對其進行測驗,但是 - 這是這種情況下的一般預期模式。所以你會用一個包裝它:
try
{
// ...
}
catch (OperationCancelledException) when (cancellationToken.IsCancellationRequested)
{
// treat as completion; swallow
}
或者:您可以傳入CancellationToken.None通道讀取 API,并僅使用撰寫器的完成來表示退出(確保.Complete(...)在退出時呼叫撰寫器)。
也就是說:ReadAllAsync可能不是這里的首選 API,因為您并不真正需要它IAsyncEnumerable<T>- 所以使用本機通道 API 可能更可取,即
while (await _output.Reader.WaitToReadAsync(cancellationToken))
{
while (_output.Reader.TryRead(out var message))
{
// ...
}
}
uj5u.com熱心網友回復:
我不確定代表Task回傳的是什么StartAsync:
public async Task StartAsync(CancellationToken cancellationToken)
{
var receiving = ReceiveLoopAsync(cancellationToken);
var sending = SendLoopAsync(cancellationToken);
var completedTask = await Task.WhenAny(receiving, sending).ConfigureAwait(false);
if (completedTask.Exception != null)
{
Console.WriteLine("Exception");
}
}
似乎它代表了任何一個receiving和sending任務的完成,這很奇怪。這很可能是嘗試記錄任務例外的意外結果。有比這更好的記錄任務例外的方法,最簡單的方法是將異步方法中的所有代碼包含在try/catch塊中。除此之外,Exceptiona 的屬性Task只有在 task 時才為非空IsFaulted,而不是在 it 時IsCanceled。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/458727.html
標籤:C# 。网 system.threading.channels
