Как продолжить TaskCompletionSource <> в другом потоке? - PullRequest
0 голосов
/ 08 января 2020

Я использую TaskCompletionSource<> довольно часто. У меня есть проект сетевого протокола, где я получаю много потоков в одном соединении TCP / IP. Я демультиплексирую эти потоки и затем информирую соответствующие «SubConnections» о новом контенте.

Эти «SubConnections» (ожидающие через await) затем должны продолжить в новом потоке.

Обычно Я решаю такие проблемы, помещая вызов TaskComplectionSource<>.Set в анонимный метод ThreadPool.QueueUserWorkItem, например:

ThreadPool.QueueUserWorkItem(delegate { tcs.SetResult(null); });

Если я не сделаю этого, соответствующий вызов await tcs.Task продолжится в потоке, который называется tcs.SetResult.

Тем не менее, я знаю, что это не правильный способ делать вещи. Также можно самостоятельно написать SynchronizationContext (или что-то в этом роде), который будет инструктировать вызов await для продолжения в другом потоке.

Мой основной вопрос здесь: Как бы я это сделал в способ «лучшей практики»?

Я также надеюсь избежать издержек ThreadPool, потому что он довольно высок на Linux по сравнению с простой блокировкой потока и ожиданием ManualResetEvent - даже если SynchronizationContext (или что-то еще) может также использовать ThreadPool.

Пожалуйста, не говорите мне, что вообще плохая идея мультиплексировать что-то в одном соединении tcp / ip или что Я должен просто использовать System.IO.Pipelines, REST или что-то еще. Это мой сценарий. Спасибо.

1 Ответ

1 голос
/ 08 января 2020

Вы можете создать TaskCompletionSource, используя TaskCreationOptions.RunContinuationsAsynchronously (дюймы NET 4.6 +):

var tcs = new TaskCompletionSource<Result>(TaskCreationOptions.RunContinuationsAsynchronously);
...
tcs.SetResult(...);

См., Например, эту тему для подробнее ...

...