Должны ли задачи, генерируемые TaskCompletionSource, быть Dispose () d? - PullRequest
0 голосов
/ 19 февраля 2019

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

В соответствии с этим вопросом Нужно ли мне распоряжаться заданием? и согласно этому блогу Параллельное программирование с .NET Task s не обязательно должно быть Dispose d.Тем не менее, я иногда создаю множество тысяч 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);
}

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

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

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

1 Ответ

0 голосов
/ 19 февраля 2019

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

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

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

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

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

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

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

...