C# 如果在X分钟内没有新项目进入“通道”,如何读取小于批量大小的“通道”中的剩余项目
我正在使用C# 如果在X分钟内没有新项目进入“通道”,如何读取小于批量大小的“通道”中的剩余项目,c#,asp.net-core,system.threading.channels,C#,Asp.net Core,System.threading.channels,我正在使用System.Threading.Channels中的Channel,希望批量读取项目(5项),我有如下方法 public class Batcher { private readonly Channel<MeasurementViewModel> _channel; public Batcher() { _channel = Channel.CreateUnbounded<MeasurementViewModel>();
System.Threading.Channels
中的Channel
,希望批量读取项目(5项),我有如下方法
public class Batcher
{
private readonly Channel<MeasurementViewModel> _channel;
public Batcher()
{
_channel = Channel.CreateUnbounded<MeasurementViewModel>();
}
public async Task<MeasurementViewModel[]> ReadBatchAsync(int batchSize, CancellationToken stoppingToken)
{
var result = new MeasurementViewModel[batchSize];
for (var i = 0; i < batchSize; i++)
{
result[i] = await _channel.Reader.ReadAsync(stoppingToken);
}
return result;
}
}
public class WriterService : BackgroundService
{
private readonly Batcher _batcher;
public WriterService(Batcher batcher)
{
_batcher = batcher;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var batchOfItems = await _batcher.ReadBatchAsync(5, stoppingToken);
var range = string.Join(',', batchOfItems.Select(item => item.Value));
var x = range;
}
}
}
这是有效的,每当频道中有5个项目时,我就会得到范围
问题是,当频道中只剩下2个项目时,由于过去10分钟没有项目进入频道,那么如何读取频道中剩余的2个项目?您可以创建一个取消令牌源
,这样您就可以同时监视外部取消请求,以及内部引发的超时。下面是通过为类创建ReadBatchAsync
扩展方法来使用此技术的示例:
先生,你让我高兴极了。非常好,非常感谢!!!!
public static async ValueTask<T[]> ReadBatchAsync<T>(
this ChannelReader<T> channelReader,
int batchSize, TimeSpan timeout, CancellationToken cancellationToken = default)
{
// Arguments validation omitted
var items = new List<T>(batchSize);
using (var linkedCTS
= CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
linkedCTS.CancelAfter(timeout);
while (true)
{
var token = items.Count == 0 ? cancellationToken : linkedCTS.Token;
T item;
try
{
item = await channelReader.ReadAsync(token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
cancellationToken.ThrowIfCancellationRequested();
break; // The cancellation was induced by timeout (ignore it)
}
catch (ChannelClosedException)
{
if (items.Count == 0) throw;
break;
}
items.Add(item);
if (items.Count >= batchSize) break;
}
}
return items.ToArray();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (true)
{
MeasurementViewModel[] batch;
try
{
batch = await _channel.Reader.ReadBatchAsync(
5, TimeSpan.FromMinutes(10), stoppingToken);
}
catch (OperationCanceledException) { return; }
catch (ChannelClosedException) { break; }
Console.WriteLine(String.Join(',', batch.Select(item => item.Value)));
}
await _channel.Reader.Completion; // Propagate possible failure
}