是否有一个内置的有限长度包装列表(从结束包装开始),您只能访问添加的最后n个元素



我需要在列表/数组中保留元素,这样我就可以访问最后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类本身除了ReaderWriter属性之外没有任何有用的成员
  • 写作和阅读是明显异步的
  • 写入和读取顺序都被保留
  • 通道可以是无边界的,也可以是有边界的。一个无界的渠道可以无限增长,当读者比作家慢时,这可能是一个问题。有了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 theIAsyncEnumerable<gt;returned byChannelReader.ReadAllAsync`读取消息:

async Task ConsumeAsync(ChannelReader<int> input,CancellationToken cancellationToken)
{
await foreach(var msg in input.ReadAllAsync(cancellationToken))
{
await DoSomething(msg);
}
}

最新更新