2011-12-12 26 views
6

Đây có lẽ là một trong những điều cơ bản nhất trong F #, nhưng tôi vừa mới nhận ra rằng tôi không biết chuyện gì đang diễn ra đằng sau những tên tuổi.Chờ mà không chặn chủ đề? - Làm sao?

let testMe() = 
    async { printfn "before!" 
      do! myAsyncFunction() // Waits without blocking thread 
      printfn "after!" } 

testMe |> Async.RunSynchronously 

Điều gì đang xảy ra tại do! myAsyncFunction()? Tôi biết rằng nó đợi myAsyncFunction kết thúc, trước khi tiếp tục. Nhưng làm thế nào nó có thể làm điều đó, mà không chặn luồng?

phỏng đoán tốt nhất của tôi là mọi thứ sau do! myAsyncFunction() được chuyển thành tiếp tục, được thực hiện trên cùng một luồng myAsyncFunction() được lên lịch, sau khi myAsyncFunction() hoàn tất việc thực thi .. nhưng sau đó lại là đoán.

+1

Đoán của bạn là đúng, mặc dù tôi cho rằng việc tiếp tục sẽ được chạy trên chuỗi có sẵn tiếp theo từ nhóm chủ đề, không nhất thiết phải cùng một chuỗi. – Daniel

Trả lời

5

Khi bạn chỉ ra chính xác, myAsyncFunction được chuyển tiếp và nó gọi nó để tiếp tục phần còn lại của luồng công việc không đồng bộ khi hoàn thành.

Bạn có thể hiểu nó tốt hơn bằng cách nhìn vào phiên bản khử đường của mã:

let testMe() = 
    async.Delay(fun() -> 
    printfn "before!" 
    async.Bind(myAsyncFunction(), fun() -> 
     printfn "after!" 
     async.Zero())) 

Họ Điều quan trọng là các công việc không đồng bộ được tạo ra bởi myAsyncFunction được trao cho các hoạt động Bind bắt đầu nó và đưa nó trở thành đối số thứ hai (tiếp tục) làm hàm để gọi khi luồng công việc hoàn tất. Nếu bạn đơn giản hóa rất nhiều, sau đó là một công việc không đồng bộ có thể được định nghĩa như thế này:

type MyAsync<'T> = (('T -> unit) * (exn -> unit)) -> unit 

Vì vậy, một công việc không đồng bộ chỉ là một chức năng mà phải mất một số continuations như là đối số. Khi nó được tiếp tục, nó làm một cái gì đó (tức là tạo ra một bộ đếm thời gian hoặc bắt đầu I/O) và sau đó nó cuối cùng gọi các tiếp tục này. Câu hỏi "Các chuỗi liên tục được gọi là gì?" là một điều thú vị - trong một mô hình đơn giản, nó phụ thuộc vào số MyAsync mà bạn đang bắt đầu - nó có thể quyết định chạy chúng bất cứ nơi nào nó muốn (tức là Async.SwithcToNewThread chạy chúng trên một chuỗi mới). Thư viện F # bao gồm một số xử lý bổ sung làm cho việc lập trình GUI sử dụng quy trình công việc dễ dàng hơn.

Ví dụ của bạn sử dụng Async.RunImmediate, chặn chuỗi hiện tại nhưng bạn cũng có thể sử dụng Async.Start, chỉ bắt đầu luồng công việc và bỏ qua kết quả khi được tạo. Việc triển khai Async.Start có thể trông giống như sau:

let Start (async:MyAsync<unit>) = async (ignore, ignore) 
Các vấn đề liên quan