2012-03-28 205 views
1

我從Bloomberg API檢索數據,並且對緩慢感到非常驚訝。 我的計算是由此限制的IO。將線程阻塞轉換爲f中的非線程阻塞#

因此,我決定使用一些異步monad生成器來取消它。 運行它後,結果並沒有那麼好,這是顯而易見的,因爲我調用了線程阻塞的函數NextEvent。

 let outerloop args dic = 
     ... 
     let rec innerloop continuetoloop = 
      let eventObj = session.NextEvent(); //This blocks 
      ... 

    let seqtable = reader.ReadFile(@"C:\homeware\sector.csv", ";".[0], true) 

    let dic = ConcurrentDictionary<_,_>() 
    let wf = seqtable |> Seq.mapi (fun i item -> async { outerloop item dic }) 
    wf |> Async.Parallel 
     |> Async.RunSynchronously 
     |> ignore 
    printfn "%A" ret 

是否有來包裝到阻塞調用非阻塞通話的好辦法? 此外,爲什麼異步框架沒有創建儘可能多的線程,因爲我有請求(如200)?當我檢查我從中得到的值我看到的只有4-5所使用的線程..

UPDATE

我發現爲什麼它會永遠不可能令人信服的理由。 異步操作使用異步指令後的內容並將其安排在線程池中的某處。只要異步函數的使用是正確的,也就是說,總是返回它所源自的線程池,我們可以認爲我們是在一個線程上執行。

單線程意味着所有的調度將總是在稍後的某個地方執行,並且阻塞指令無法避免這樣的事實:最終一旦它運行,它將不得不在未來某個時刻阻塞worflow。

+0

如何創建200個線程以任何方式幫助您?如果你有200個連接,你將有200個非常慢的連接,而不是幾個快速連接。 (不提200 MB的開銷。) – svick 2012-03-28 11:12:41

+0

另外,如果你的操作是IO阻塞,那麼使用更多的CPU不會給你帶來太多好處。速度很慢,因爲網絡速度很慢,並且您不會通過使用更多線程來提高網絡速度。 – svick 2012-03-28 11:23:14

+0

@svick爲什麼連接IO計算速度慢的連接不會比5個慢速連接好40倍?我可以看到它現在正在處理40個5個操作,這可以通過200個操作中的1個操作更好地處理。或者我錯過了什麼? – nicolas 2012-03-28 12:18:20

回答

2

有沒有一種很好的方法將該阻塞呼叫包裹到非阻塞呼叫?

不可以。您永遠無法打包阻止的呼叫以使它們成爲非阻塞。如果可以的話,異步只是一種設計模式,而不是一種基本的範式轉變。

此外,爲什麼異步框架沒有創建儘可能多的線程,因爲我有請求(如200)?

異步建立在線程池上,線程池被設計爲不積極創建線程,因爲它們非常昂貴。 (真正的)異步的完整點在於,它不需要與連接一樣多的線程。您可以使用約30個線程處理10,000個同時連接。

您似乎對異步是什麼以及它是什麼有一個完全的誤解。我建議購買任何涵蓋此主題並閱讀它的F#書籍。特別是,您的解決方案不是異步的,因爲您只需在異步工作流程內調用您的阻止StartGetFieldsValue成員,就會破壞異步的目的。您可能只需做Array.Parallel.map getFieldsValue

此外,您希望在並行執行某些操作時使用純功能API,而不是在原地進行變異ConcurrentDictionary。因此,與

let! result = req.StartGetFieldsValue() 
... 
return result 

取代req.StartGetFieldsValue retdict取代ignore

+0

我並不希望爲第一個pb使用異步解決方案。正如我讀到的,asyncs只是CPS重寫。 (對於字典而言,如果對這個特定的API來說效率不高,可能會在幾個字段上對多個證券進行請求,並且信息會逐位進入。什麼是最有意義的最小單位?可能是一個很好的方式來打包它,但我不知道它) – nicolas 2012-03-30 22:38:12

+0

說,我肯定會讀一些材料,因爲必須有一種方法來映射這個API很好.. – nicolas 2012-03-30 22:39:35

+0

你的評論讓我想到了什麼是真正的異步計算。雖然我們可以說它們只是CPS重寫,但這只是形成代碼的一部分。如果我對此沒有錯,真實的故事是異步計算是針對*線程池*什麼同步計算針對*線程*。這就是爲什麼他們大多數時候感覺像是同步計算。正如你所指出的,線程池對於我們99%的時間所做的工作非常有用,異步結構反映了這種能力。 – nicolas 2012-03-31 13:21:58

0

這是我所做的似乎正在工作的解決方案。 當然,它不僅使用異步(減號),而且使用異步。

我定義具有一個事件,精加工,和一種方法,asyncstart簡單類型,具有作爲參數運行的方法。它啓動方法,然後觸發在適當的地方完成的情況下(在我的情況,我不得不捕捉同步上下文等)

然後在消費者方面,我用簡單的

let! completion = Async.Waitfromevent wapper.finished |> Async.StartAsChild 
let! completed = completion 

雖然運行這個代碼,在消費者方面,我只使用異步調用,使我的代碼不被阻塞。當然,必須有一些線程被阻塞,但這種情況發生在我的主要服務環路之外,它仍然是被動和適應的。