F # горячий, чтобы остановить Async.Start

Sep 04 2020

Привет, у меня вопрос об асинхронности в F #.

Итак, у меня есть простая процедура, которая выполняется в фоновом режиме, помещается в член типа и выглядит так:

type Sender () = 
     member this.Start udpConectionPool = 
        async { (* ome operation that continusly send something to throu udp*) } |> Async.Start

Итак, это начинается и начинает непрерывно отправлять кадры через UDP, не блокируя остальную часть программы, но время от времени я хочу перезапустить поток (скажем, я хочу добавить новую конечную точку, она отправит ее, это параметр udpConectionPool).

Я думал о чем-то вроде передачи задачи участнику, а затем:

member this.Stop = async { do! (*stop async start member that contains task*)}

И затем я могу перезапустить эту задачу с обновленным пулом соединений, но я не знаю, смогу ли я это сделать. У меня вопрос: можно ли остановить такую ​​задачу, или, если нет, есть лучший способ сделать это?

Ответы

4 TomasPetricek Sep 04 2020 at 20:56

Стандартный способ отмены асинхронных рабочих процессов F # - использование файла CancellationToken. При звонке Async.Startвы можете предоставить жетон отмены. Когда токен отменяется, асинхронный рабочий процесс останавливается (после завершения текущей работы по блокировке):

open System.Threading

let cts = new CancellationTokenSource()
let work = async { (* ... *) }
Async.Start(work, cts.Token)

cts.Cancel() // Sometime later from another thread

Чтобы интегрировать это с Sender, вы можете либо сохранить текущий, либо CancellationTokenSourceиметь Stopметод, который его отменяет (если вы хотите сохранить это внутри класса с отслеживанием состояния). В качестве альтернативы вы можете вернуться IDisposableиз Startметода аналогично тому, как Observableработает интерфейс:

type Sender () = 
  member this.Start udpConectionPool = 
    let cts = new CancellationTokenSource()
    let work = async { (* ... *) }
    Async.Start(work, cts.Token)
    { new System.IDisposable with
      member x.Dispose() = cts.Cancel() }

Таким образом, вызывающий Startобъект несет ответственность за сохранение возвращенного IDisposableи утилизацию его перед Startповторным вызовом .