Непрерывный цикл F# в F#
у меня есть сервер сокетов, который должен работать на цикле, принимающем клиентов, поэтому я узнал, что в функциональном программировании используется рекурсивный цикл:
let awaitConnections (wsl:WebSocketListener) =
let rec loop ()=
async {
let! ws = Async.AwaitTask (wsl.AcceptWebSocketAsync(cancellation.Token) )
printfn "Connection from %s" (ws.RemoteEndpoint.Address.ToString())
Async.Start <| awaitMessages ws
do! loop()}
loop()
и этот код вызывается следующим образом:
Async.Start <| awaitConnections listener
учитывая, что приложение работает непрерывно, следует ли использовать итеративный подход вместо этого? Делает rec
подход создает вложенные стеки казнь?
кроме того, я хотел бы сделать что-то после цикла заканчивается, например:
let awaitConnections (wsl:WebSocketListener) =
let rec loop ()=
async {
let! ws = Async.AwaitTask (wsl.AcceptWebSocketAsync(cancellation.Token) )
printfn "Connection from %s" (ws.RemoteEndpoint.Address.ToString())
Async.Start <| awaitMessages ws
do! loop()}
loop()
printf "The loop ended" // <-- this line
но тогда он не может скомпилировать, потому что awaitConnections
тип возвращаемого значения. Как я мог это сделать? Я все делаю правильно?
1 ответов
вы, безусловно, на правильном пути! Вот простой пример, который демонстрирует, что вам нужно сделать:
// Loop that keeps running forever until an exception happens
let rec loop () = async {
do! Async.Sleep(1000)
printfn "Working"
return! loop () }
// Call the loop in a try .. finally block to run some cleanup code at the end
let main () = async {
try
do! loop ()
finally
printfn "That's it!" }
// Start the work in the background and create a cancellation token
let cts = new System.Threading.CancellationTokenSource()
Async.Start(main (), cts.Token)
// To cancel it, just call: cts.Cancel()
несколько важных моментов:
вы не можете запустить код после завершения бесконечного цикла (он бесконечен!), но вы можете использовать
try .. finally
для запуска некоторого кода при отмене блокаобратите внимание, что с помощью
return!
для рекурсивного цикла лучше использоватьdo!
создает памяти подтеки.вы можете отменить вычисление с помощью токена отмены-просто передайте токен при его запуске.