C# 如何避免ChannelReader.WaitToReadSync时引发InvalidOperationException?
我使用System.Threading.Channel编写了异步队列。 但当我运行程序进行测试时,以下异常在随机时间抛出,工作线程停止C# 如何避免ChannelReader.WaitToReadSync时引发InvalidOperationException?,c#,multithreading,async-await,system.threading.channels,C#,Multithreading,Async Await,System.threading.channels,我使用System.Threading.Channel编写了异步队列。 但当我运行程序进行测试时,以下异常在随机时间抛出,工作线程停止 System.InvalidOperationException: The asynchronous operation has not completed. at System.Threading.Channels.AsyncOperation.ThrowIncompleteOperationException() at System.Thread
System.InvalidOperationException: The asynchronous operation has not completed.
at System.Threading.Channels.AsyncOperation.ThrowIncompleteOperationException()
at System.Threading.Channels.AsyncOperation`1.GetResult(Int16 token)
at AsyncChannels.Worker() in g:\src\gitrepos\dotnet-sandbox\channelstest\AsyncChannelsTest.cs:line 26
如果捕获到异常并忽略,则代码正在工作。
但是我想消除这个错误,因为它的原因还不清楚
这是我的环境和最少的代码
- TargetFramework=netcoreapp2.1
- System.Threading.Channel版本=4.5.0
使用System.Threading.Channels;
使用系统线程;
使用System.Threading.Tasks;
使用制度;
使用System.Linq;
类异步通道:IDisposable
{
渠道(u渠道),;
螺纹(u螺纹),;
CancellationTokenSource\u取消;
公共频道()
{
_Channel=Channel.CreateUnbounded();
_线程=新线程(工作线程);
_Thread.Start();
_取消=新的CancellationTokenSource();
}
私人空房工人()
{
while(!\u取消。请求取消)
{
//引发System.InvalidOperationException
if(!\u Channel.Reader.waitToReadSync(\u Cancellation.Token.Result)
{
打破
}
while(_Channel.Reader.TryRead(out var项))
{
项目.TrySetResult(真);
}
}
}
公共空间处置()
{
_取消;
_Channel.Writer.TryComplete();
_Thread.Join();
}
公共任务排队()
{
var tcs=新TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
_Channel.Writer.TryWrite(tcs);
返回tcs.Task;
}
公共静态异步任务测试()
{
使用(var queue=new asynchchannels())
{
对于(int i=0;i<100000;i++)
{
wait queue.Enqueue().configurewait(false);
}
}
}
}
您喜欢这样:
_Channel.Reader.WaitToReadAsync(_Cancellation.Token).Result
使用ValueTask
只能执行两件事:等待它(仅一次),或者通过调用AsTask()
将它转换为任务。如果您需要执行任何复杂的操作,如等待
多次执行或阻塞,则需要使用AsTask()
或者,在这种情况下,只需在标准频道消费模式中使用wait
:
class AsyncChannels : IDisposable
{
Channel<TaskCompletionSource<bool>> _Channel;
Task _Thread;
CancellationTokenSource _Cancellation;
public AsyncChannels()
{
_Channel = Channel.CreateUnbounded<TaskCompletionSource<bool>>();
_Thread = Task.Run(() => WorkerAsync());
_Cancellation = new CancellationTokenSource();
}
private async Task WorkerAsync()
{
try
{
while (await _Channel.Reader.WaitToReadAsync(_Cancellation.Token))
while (_Channel.Reader.TryRead(out var item))
item.TrySetResult(true);
}
catch (OperationCanceledException)
{
}
}
public void Dispose()
{
_Cancellation.Cancel();
_Channel.Writer.TryComplete();
}
...
}
类异步通道:IDisposable
{
渠道(u渠道),;
任务线程;
CancellationTokenSource\u取消;
公共频道()
{
_Channel=Channel.CreateUnbounded();
_Thread=Task.Run(()=>WorkerAsync());
_取消=新的CancellationTokenSource();
}
专用异步任务WorkerAsync()
{
尝试
{
while(wait_Channel.Reader.WaitToReadAsync(_Cancellation.Token))
while(_Channel.Reader.TryRead(out var项))
项目.TrySetResult(真);
}
捕获(操作取消异常)
{
}
}
公共空间处置()
{
_取消;
_Channel.Writer.TryComplete();
}
...
}
您喜欢这样:
_Channel.Reader.WaitToReadAsync(_Cancellation.Token).Result
使用ValueTask
只能执行两件事:等待它(仅一次),或者通过调用AsTask()
将它转换为任务。如果您需要执行任何复杂的操作,如等待
多次执行或阻塞,则需要使用AsTask()
或者,在这种情况下,只需在标准频道消费模式中使用wait
:
class AsyncChannels : IDisposable
{
Channel<TaskCompletionSource<bool>> _Channel;
Task _Thread;
CancellationTokenSource _Cancellation;
public AsyncChannels()
{
_Channel = Channel.CreateUnbounded<TaskCompletionSource<bool>>();
_Thread = Task.Run(() => WorkerAsync());
_Cancellation = new CancellationTokenSource();
}
private async Task WorkerAsync()
{
try
{
while (await _Channel.Reader.WaitToReadAsync(_Cancellation.Token))
while (_Channel.Reader.TryRead(out var item))
item.TrySetResult(true);
}
catch (OperationCanceledException)
{
}
}
public void Dispose()
{
_Cancellation.Cancel();
_Channel.Writer.TryComplete();
}
...
}
类异步通道:IDisposable
{
渠道(u渠道),;
任务线程;
CancellationTokenSource\u取消;
公共频道()
{
_Channel=Channel.CreateUnbounded();
_Thread=Task.Run(()=>WorkerAsync());
_取消=新的CancellationTokenSource();
}
专用异步任务WorkerAsync()
{
尝试
{
while(wait_Channel.Reader.WaitToReadAsync(_Cancellation.Token))
while(_Channel.Reader.TryRead(out var项))
项目.TrySetResult(真);
}
捕获(操作取消异常)
{
}
}
公共空间处置()
{
_取消;
_Channel.Writer.TryComplete();
}
...
}
是否调试,是否确定在Dispose期间取消任务时不会出现异常?是否调试,是否确定在Dispose期间取消任务时不会出现异常?