Почему Async.StartChild не принимает CancellationToken? - PullRequest
0 голосов
/ 10 мая 2018

Я изо всех сил пытаюсь понять Async.[StartChild|Start] Дизайн API. Я хотел бы запустить асинхронный процесс, который выполняет чтение потока tcp и вызывает обратный вызов в соответствии с командами, поступающими на tcp.

Поскольку этот асинхронный процесс на самом деле не возвращает ни одного значения, похоже, что я должен использовать Async.Start. В какой-то момент я хочу «закрыть» мой tcp-клиент, и `Async.Start принимает CancellationToken, что дает мне возможность реализовать 'close'. Пока все хорошо.

Проблема в том, что я хотел бы знать, когда клиент tcp завершает работу с отменой. Выполняется некоторая работа по очистке буфера, как только запрашивается Cancel, поэтому я не хочу завершать работу приложения, пока клиент tcp не завершит очистку. Но Async.Start возвращает единицу, что означает, что у меня нет возможности узнать, когда такой асинхронный процесс завершен. Итак, похоже, Async.StartChild должно помочь. Я должен быть в состоянии вызвать отмену, и когда очистка будет завершена, эта асинхронная вызовет следующую установку в цепочке (или сгенерирует исключение?). Но ... Async.StartChild не принимает CancellationToken, только тайм-аут.

Почему Async.StartChild реализует только один случай стратегии отмены (тайм-аут) вместо предоставления более общего способа (принять CancellationToken)?

1 Ответ

0 голосов
/ 10 мая 2018

Чтобы ответить на первую часть вопроса - если вам нужно выполнить некоторую работу по очистке, вы можете просто поместить ее в finally, и она будет вызвана, когда рабочий процесс отменяется. Например:

let work = 
  async {
    try
      printfn "first work"
      do! Async.Sleep 1000
      printfn "second work"
    finally
      printfn "cleanup" }

Допустим, вы запустили это с помощью Async.Start, подождите 500 мс, а затем отмените вычисление:

let cts = new System.Threading.CancellationTokenSource()
Async.Start(work, cts.Token)
System.Threading.Thread.Sleep(500)
cts.Cancel()

Вывод будет "первая работа, очистка". Как видите, при отмене вычислений будут выполняться все предложения finally.

Чтобы ответить на вторую часть вопроса - если вам нужно дождаться завершения работы, вы можете использовать RunSynchronously (но тогда, возможно, вам на самом деле не нужны асинхронные рабочие процессы, если вы все равно блокируете ...) .

Следующее запускает фоновый процесс, который отменяет основную работу через 500 мс, а затем синхронно начинает основную работу:

let cts = new System.Threading.CancellationTokenSource()

async {
  do! Async.Sleep(500)
  cts.Cancel() } |> Async.Start

try Async.RunSynchronously(work, cancellationToken=cts.Token)
with :? System.OperationCanceledException -> ()
printfn "completed"

Это печатает «первая работа, очистка, завершена» - как вы можете видеть, вызов RunSynchronously был заблокирован, пока работа не была отменена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...