我需要在列表/数组中保留元素,这样我就可以访问最后n个元素。也就是说,我一直在添加,如果需要的话,应该可以从中获得最后的元素。(就像一个只保存最后n个小时的安全摄像头一样。(我想有一个List或数组,并在索引环绕的地方维护一个索引。
但这似乎是一个有用的结构,所以我想知道它是否已经存在于.Net中。如果已经存在,就不需要重新发明轮子了。
那么,这样的东西存在于.Net中吗?
编辑
显然,这里存在一个如何实现的问题。这个问题和最重要的答案来自10多年前。这并不能回答我的问题,即它是否是内置的今天。我们今天使用的很多在当时并不存在。此外,使用Queue也没有帮助,因为我需要能够访问每个元素(最多n个(,而不仅仅是最后一个。
这描述了一个循环或环形缓冲区。实现一个相对容易,谷歌或搜索NuGet会返回许多实现,包括C5库中的CircularQueue。
对于异步操作,可以使用BoundedChannel FullMode.DropOldest:配置的BounddChannel
var options=new BoundedChannelOptions
{
Capacity = 10,
FullMode = BoundedChannelFullMode.DropOldest
};
var channel=Channel.CreateBounded<float>(options);
var writer=channel.Writer;
while(!cancellationToken.IsCancellationRequested)
{
var value=await getSomeValue(cancellationToken);
await writer.WriteAsync(value,cancellationToken);
}
writer.Complete();
通道是用于生产者/消费者场景的专用异步队列,因此它们的API和行为与正常队列大不相同。
- 编写器和读取器(生产者和消费者(使用不同的API来编写(ChannelWriter和读取ChannelReader(。Channel类本身除了
Reader
和Writer
属性之外没有任何有用的成员 - 写作和阅读是明显异步的
- 写入和读取顺序都被保留
- 通道可以是无边界的,也可以是有边界的。一个无界的渠道可以无限增长,当读者比作家慢时,这可能是一个问题。有了Bounded通道,一旦通道达到上限,它就可以(异步(阻止写入程序或丢弃最旧或最新的项目
信道被使用,例如在SignalR服务器到客户端的流传输中,以产生服务器事件。doc示例使用了一个无边界的拥有的通道,即其生存期由生产者方法控制的通道。这很容易成为DropOldest的有界通道。如果我们只想发送";新鲜的";潜在慢速订阅者的事件:
public ChannelReader<int> Counter(
int count,
int delay,
CancellationToken cancellationToken)
{
var options=new BoundedChannelOptions
{
Capacity = 10,
FullMode = BoundedChannelFullMode.DropOldest
};
var channel=Channel.CreateBounded<int>(options);
// We don't want to await WriteItemsAsync, otherwise we'd end up waiting
// for all the items to be written before returning the channel back to
// the client.
_ = WriteItemsAsync(channel.Writer, count, delay, cancellationToken);
return channel.Reader;
}
private async Task WriteItemsAsync(
ChannelWriter<int> writer,
int count,
int delay,
CancellationToken cancellationToken)
{
Exception localException = null;
try
{
for (var i = 0; i < count; i++)
{
await writer.WriteAsync(i, cancellationToken);
// 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)
{
localException = ex;
}
finally
{
writer.Complete(localException);
}
}
如果我们将容量设置为1
,则得到Publish Latest
行为:
public ChannelReader<int> CounterLatest(
int count,
int delay,
CancellationToken cancellationToken)
{
var options=new BoundedChannelOptions
{
Capacity = 1,
FullMode = BoundedChannelFullMode.DropOldest
};
var channel=Channel.CreateBounded<int>(options);
// We don't want to await WriteItemsAsync, otherwise we'd end up waiting
// for all the items to be written before returning the channel back to
// the client.
_ = WriteItemsAsync(channel.Writer, count, delay, cancellationToken);
return channel.Reader;
}
消费者使用ChannelReader and eg the
IAsyncEnumerable<gt;returned by
ChannelReader.ReadAllAsync`读取消息:
async Task ConsumeAsync(ChannelReader<int> input,CancellationToken cancellationToken)
{
await foreach(var msg in input.ReadAllAsync(cancellationToken))
{
await DoSomething(msg);
}
}