我正在实现一个异步缓冲系统,我希望队列的一个消费者能够保证项目按顺序处理。消费者应该定期检查队列,处理其中的所有项目,然后“睡眠”一段时间。 Task.Delay() 似乎非常适合这样的系统,因为与 Thread.Sleep() 不同,它在睡眠时不会消耗线程,并且与 Timer 不同,如果处理队列项花费的时间超过睡眠间隔,它不会启动新线程。但是,我想知道如果任务系统正在跟踪原始任务的整个延续列表,在 while 循环中使用 Task.Delay() 是否会造成内存泄漏。作为参考,我的系统如下所示:
void EnqueueItem(Item item) {
lock (this._lock) { this._items.Add(item); }
}
async Task Consumer() {
while (true) {
await Task.Delay(interval).ConfigureAwait(false);
Item[] items = null;
lock (this._lock) {
if (this._disposed) { return; }
if (this._items.Count > 0)
{
items = this._items.ToArray();
this._items.Clear();
}
}
if (items != null) { Process(items); }
}
}
// in the constructor of the buffer
this.Consumer();
我正在实现一个异步缓冲系统...
我强烈建议您使用现有的。 TPL Dataflow 是我的首要推荐。但如果您的平台上不可用,那么 my
AsyncProducerConsumerQueue
是一个选项。
此设置允许您的消费者仅使用
ReceiveAsync
/DequeueAsync
,而无需 Task.Delay
。
也就是说,我不相信会出现像你所描述的那样的内存泄漏。不过,我实际上还没有在分析器中运行它来验证这一点。
它不会导致内存泄漏,但是如果您处于紧密循环中,您可能想要处理任务而不是等待它们的终结器
例如
var t = Task.Delay(interval);
await t.ConfigureAwait(false);
t.Dispose();
但您可能不想,也不应该需要(请参阅我需要处置任务吗?)
是的,它可能会泄漏内存。
[Test]
public async Task TaskDelay()
{
for (int i = 0; i < int.MaxValue; i++)
{
var t = Task.Delay(i);
await Task.WhenAny(t, NoOp());
}
}
public async Task NoOp()
{
await Task.Yield();
}
会泄漏内存。
取消令牌需要传递给
Task.Delay
,并且需要取消它以阻止泄漏,例如这个不会漏的
public async Task TaskDelay()
{
for (int i = 0; i < int.MaxValue; i++)
{
using var cts = new CancellationTokenSource();
var t = Task.Delay(i, cts.Token);
await Task.WhenAny(t, NoOp());
cts.Cancel();
}
}