【问题标题】:Does a loop with Task.Delay() create a memory leak?Task.Delay() 的循环是否会造成内存泄漏?
【发布时间】:2014-01-09 09:33:55
【问题描述】:

我正在实现一个异步缓冲系统,我希望队列中只有一个消费者来保证项目是按顺序处理的。消费者应该定期检查队列,处理其中的所有项目,然后“睡眠”一段时间。 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();

【问题讨论】:

  • 我之前使用过计时器方法,现在只使用Monitor.TryEnter 方法。如果它无法获得锁,它可以直接退出该方法而不做任何事情。这意味着可能会创建一个线程,但它不会存在很长时间。或者,您可以在每个流程循环的开始和结束时停止和启动计时器。
  • 一旦任务完成并且您的代码删除任务对象引用,任务的延续列表将自动被垃圾收集。 Task.Delay 对此没有任何影响,除了让任务运行的时间超过可能需要的时间。
  • 与您的问题无关,但是如果您从构造函数中调用Consumer(),当Process() 抛出异常时会发生什么?
  • @svick 在实际代码中,正是出于这个原因,Process() 调用被包装在 try-catch 中(错误记录在 catch 中)

标签: c# task async-await


【解决方案1】:

我正在实现一个异步缓冲系统...

我强烈建议您使用现有的。 TPL Dataflow 是我的首选。但是,如果您的平台上没有此功能,则可以选择 my AsyncProducerConsumerQueue

此设置允许您的消费者只使用ReceiveAsync/DequeueAsync 而不需要Task.Delay

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

【讨论】:

  • 您介意发布一个使用 TPL 数据流的示例吗?在这种情况下,我将单个轮询器定期批量处理的大量项目排入队列(我想要延迟以便可以建立一堆项目)。这就是为什么我不使用像 BlockingCollection 这样的东西,它专注于一次入队/出队 1 个对象。
  • 好的;我不知道批处理要求。在这种情况下,您几乎肯定想要使用 Reactive Extensions。它们具有可以根据时间间隔进行批处理的内置操作。
  • @ChaseMedallion 作为 Rx 的替代方案,您可以使用 BatchBlock 并从计时器调用它的 TriggerBatch()。或者,如果批处理应该由消费者的速度控制,请查看this question
【解决方案2】:

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

例如

var t = Task.Delay(interval);
await t.ConfigureAwait(false);
t.Dispose();

但你可能不想,也不应该需要(见Do I need to dispose of Tasks?

【讨论】:

  • 该链接对我来说是 403
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 2014-09-16
  • 2012-04-09
  • 2016-05-31
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多