Должны ли задачи, сгенерированные 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>
,