Должны ли задачи, сгенерированные TaskCompletionSource быть Dispose()d?

Я использую TaskCompletionSource в моем программном обеспечении для распространения сетевых пакетов async / await методы. Так что в моем коде есть различные моменты, когда программное обеспечение должно ожидать демультиплексирования сетевого пакета из обработчика приема и передачи его методу async Wait(), Может быть много, много пакетов в секунду, и я решаю, хочу ли я отправить пакет в TaskCompletionSource или положить его в Queue, Таким образом, всякий раз, когда нет TaskCompletionSource Я создам новый, который приводит к новому Task объект.

В соответствии с этим вопросом Нужно ли распоряжаться заданием? и в соответствии с этим блогом параллельное программирование с.NET Task не нужно быть Dispose д. Тем не менее, я иногда инстанцирую много тысяч TaskCompletionSource в секунду. Подробный ответ в связанном блоге также говорит, что Task может использовать внутри WaitHandle, Теперь у меня есть сильное чувство, что мой случай является именно тем случаем, где я должен использовать Dispose на задачах из TaskCompletionSource,

Вот так я жду новый пакет. Этот метод будет вызываться с await и также может быть сильно вызван параллельно:

public async Task<Packet> Wait()
{
    Packet packet;

    lock (sync)
        if (packets.TryDequeue(out packet))
            return packet;
        else
            waiter = new TaskCompletionSource<Packet>();

    return await waiter.Task;
}

Мой метод отправки пакетов из сетевого обработчика выглядит следующим образом:

public void Poke(Packet packet)
{
    lock (sync)
        if (waiter == null)
            packets.Enqueue(packet);
        else
            waiter.SetResult(packet);
}

Я на.NET Core >= 2.2. В записи блога говорится, что поведение WaitHandle также изменился в.NET 4.5.

Вопрос: нужно ли избавляться Task в этом конкретном сценарии? Я создам много Handles если я не Dispose Задачи, созданные TaskCompletionSource при получении многих пакетов, идущих по этому пути кода? Это сценарий, о котором меня предупреждала запись в блоге?

Пожалуйста, не говорите мне, что этот метод плохой, если вы не можете сказать мне, что лучший метод очень совместим с async / await шаблон, а также возможность распространять эти пакеты среди различных выбранных слушателей. Пожалуйста, также не говорите мне, что создание большого количества объектов из-за множества сетевых пакетов, как правило, плохая идея.

1 ответ

Решение

Это сценарий, о котором меня предупреждала запись в блоге?

Вопрос "нужно ли мне этим распоряжаться? Task?"можно ответить только по тому, как выполняется задача. В частности, рассмотрите эту цитату из поста в блоге:

единственный способ размещения WaitHandle - это если вы явно запросите IAsyncResult.AsyncWaitHandle Задачи, и это должно быть довольно редко.

Ответ Рида был верным в то время, но это уже не тот случай, когда в продолжениях используются AsyncWaitHandle, В эти дни ничто не будет использовать AsyncWaitHandle неявно, так что вы должны только рассмотреть Dispose ИНГ Task s если ваш потребительский код рассматривает задачу как IAsyncResult и доступ к AsyncWaitHandle имущество. И даже тогда вы должны только рассмотреть возможность их утилизации; это не строго необходимо.

Пожалуйста, не говорите мне, что этот метод является плохим выбором, если вы не можете сказать мне, что лучший метод очень совместим с шаблоном async / await, а также может распределять эти пакеты по различным выбранным слушателям.

Я бы порекомендовал построить асинхронно-совместимую очередь производителя / потребителя как отдельный тип; Я думаю, что это поможет вашему коду быть более понятным. Вы могли бы использовать BufferBlock<T> тип асинхронной очереди из моей библиотеки AsyncEx, или создайте свой собственный, используя асинхронный монитор.

Кроме того, если вы регулярно ожидаете вашего Wait() метод, чтобы уже иметь пакет, затем рассмотрите возможность использования ValueTask<T>,

Другие вопросы по тегам