Утечка вложенной памяти IAsyncEnumerable - PullRequest
1 голос
/ 14 июля 2020

У меня есть следующий код, вызывающий утечку памяти. При использовании await внутри двух вложенных IAsyncEnumerables.

Fun c work - это функция, которая принимает входные данные из входного канала и возвращает IAsyncEnumerable, который повторяется по помещению в выходной канал.

Если я использую одну из двух строк, помеченных // Works!, код работает, как ожидалось, без создания огромной кучи.

Просмотр профилировщика памяти без утечки памяти , все выглядит нормально, объект DTO (TOut) result, возвращаемый перечислением «работа», ссылается только на выходной канал, как и ожидалось, с максимальным значением 10 в качестве ограниченного.

При запуске кода с утечкой памяти каждый объект DTO из work IAsyncEnumerable хранится в памяти со ссылкой в ​​пути root, на функцию work и ссылкой на некоторую stati c переменную Dictionary<Int32,Task> [Statis variable Task.s_currentActiveTasks] как задачи, сгенерированные IAsyncEnumerator, никогда не завершаются и не удаляются.

public static ChannelReader<TOut> Pipe<TIn, TOut>(this ChannelReader<TIn> input, Func<TIn, IAsyncEnumerable<TOut>> work, CancellationToken cancellationToken = default)
{
        var output = Channel.CreateBounded<TOut>(10);

        _ = Task.Run(async () =>
        {
            try
            {
                await foreach (var item in input.ReadAllAsync(cancellationToken).ConfigureAwait(false))
                {                       
                    await foreach (var result in work(item))
                    {
                        // Memory leak!
                        await output.Writer.WriteAsync(result, cancellationToken).ConfigureAwait(false);

                        // Works!
                        //while (!output.Writer.TryWrite(result))
                        //    Thread.Sleep(1);
                        
                        // Works!
                        //output.Writer.WriteAsync(result, cancellationToken).AsTask().Wait(); 
                    }
                }

                output.Writer.Complete();
            }
            catch (Exception ex)
            {
                output.Writer.Complete(ex);
            }
        });

        return output;
}

Может ли кто-нибудь пролить некоторое представление об этой проблеме?

Если кто-то не может что-то заметить я пропустил серьезную ошибку, я постараюсь опубликовать минимально воспроизводимый пример. У меня еще нет большого опыта работы с IAsyncEnumerable.

...