2014-11-03 15 views
7

Tôi có một máy chủ socket mà cần phải chạy trên một vòng lặp chấp nhận khách hàng, vì vậy tôi phát hiện ra rằng trong chương trình funcional, một vòng lặp đệ quy được sử dụng:F # vòng lặp liên tục trong 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() 

Và mã này được gọi bằng cách thực hiện:

Async.Start <| awaitConnections listener 

Xem xét ứng dụng chạy liên tục, tôi có nên sử dụng phương pháp lặp lại thay thế không? Phương pháp rec có tạo ngăn xếp thực thi lồng nhau không?

Ngoài ra, tôi muốn làm điều gì đó sau khi vòng lặp kết thúc, như:

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 

Nhưng sau đó nó không thể biên dịch bởi vì các loại awaitConnections trở lại. Làm thế nào tôi có thể làm điều đó? Tôi làm đúng chứ hả?

Trả lời

17

Bạn chắc chắn đang đi đúng hướng! Dưới đây là một ví dụ đơn giản thể hiện những gì bạn cần làm:

// 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() 

Một vài điểm quan trọng:

  • Bạn có thể không thực sự chạy mã sau một kết thúc vòng lặp vô hạn (nó là vô hạn!) Nhưng bạn có thể sử dụng try .. finally để chạy một số mã khi khối bị hủy

  • Lưu ý rằng việc sử dụng return! để lặp lại đệ quy tốt hơn - sử dụng do! tạo rò rỉ bộ nhớ.

  • Bạn có thể hủy tính toán bằng mã thông báo hủy - chỉ cần chuyển mã thông báo khi bắt đầu.

+3

Cảm ơn! nơi tôi có thể tìm thêm thông tin về 'return!' so với 'do!'? – vtortola

+1

Đó là một câu hỏi được tải, nhưng tôi sẽ cho nó một shot. Các biểu thức tính toán như 'async' là đường cú pháp cho một chuỗi các cuộc gọi hàm và phần tử trả về là kết quả của các hàm. 'do!' định nghĩa một biểu thức trả về 'đơn vị', cái mà (trong trường hợp này) về cơ bản tạo ra một đối tượng' Async <'a> 'mới không làm gì ngoài việc đi vào một cuộc gọi đệ quy và' return! 'tránh điều này. Phải thừa nhận rằng, điều này có một số suy nghĩ về cách các đối tượng 'Async' hoạt động phía sau hậu trường để làm cho mọi thứ xảy ra. –

+0

Cảm ơn, rất hữu ích. – vtortola

Các vấn đề liên quan