C# 使用Task.Delay()的循环是否会造成内存泄漏?

C# 使用Task.Delay()的循环是否会造成内存泄漏?,c#,task,async-await,C#,Task,Async Await,我正在实现一个异步缓冲区系统,我希望队列中只有一个使用者,以保证项目是有序的进程。消费者应该定期检查队列,处理队列中的所有项目,然后“睡眠”一段时间。Task.Delay()似乎非常适合这样的系统,因为与Thread.Sleep()不同,它在睡眠时不会消耗线程,而与计时器不同,如果处理队列项目的时间长于睡眠间隔,它不会启动新线程。但是,我想知道如果任务系统正在跟踪原始任务的整个延续列表,那么在while循环中使用Task.Delay()是否会造成内存泄漏。作为参考,我的系统如下所示: void

我正在实现一个异步缓冲区系统,我希望队列中只有一个使用者,以保证项目是有序的进程。消费者应该定期检查队列,处理队列中的所有项目,然后“睡眠”一段时间。Task.Delay()似乎非常适合这样的系统,因为与Thread.Sleep()不同,它在睡眠时不会消耗线程,而与计时器不同,如果处理队列项目的时间长于睡眠间隔,它不会启动新线程。但是,我想知道如果任务系统正在跟踪原始任务的整个延续列表,那么在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();
我正在实现一个异步缓冲系统

我强烈建议您使用现有的。这是我的最高推荐。但如果在您的平台上不提供,则是一个选项

此设置允许您的使用者只使用
ReceiveAsync
/
DequeueAsync
,而不执行
任务。需要延迟


也就是说,我不相信会有像你描述的那样的内存泄漏。不过,我实际上还没有在探查器中运行它来验证这一点。

它不会导致内存泄漏,但是如果您处于一个紧密的循环中,您可能希望处置任务,而不是等待它们的终结器

e、 g


但是您可能不想,也不需要(参见)

我以前使用过timer方法,只使用了
Monitor.TryEnter
方法。如果无法获得锁,它可以不做任何事情就退出该方法。这意味着可能会创建一个线程,但它不会存在很长时间。或者,您可以在每个流程循环的开始和结束时停止和启动计时器。任务完成且代码删除任务对象引用后,任务的继续列表将自动被垃圾收集。Task.Delay对此没有影响,只是让任务运行的时间超过了可能需要的时间。这与您的问题无关,但是如果您从构造函数调用
Consumer()
,当
Process()
抛出异常时会发生什么情况?@svick在实际代码中,进程()调用被包装在try-catch中正是因为这个原因(错误记录在catch中),您介意使用TPL数据流发布一个示例吗?在这种情况下,我将大量的项目排入队列,单个轮询器会周期性地批量处理这些项目(我希望延迟,以便可以累积大量项目)。这就是为什么我不使用BlockingCollection这样的东西,它一次只让一个对象排队/退队;我不知道配料要求。在这种情况下,您几乎肯定希望使用反应式扩展。它们具有内置操作,可以根据时间间隔进行批处理。@ChaseMedallion作为Rx的替代方案,您可以使用
BatchBlock
并从计时器调用其
TriggerBatch()
。或者,如果批处理应该由消费者的速度来控制,那么请看一下。对于我来说,该链接是403
var t = Task.Delay(interval);
await t.ConfigureAwait(false);
t.Dispose();