2012-12-10 93 views
3

可能重複:
What is the Haskell response to Node.js?
How can I watch multiple files/socket to become readable/writable in Haskell?非阻塞IO哈斯克爾

是否可以寫在一個非阻塞的方式像的NodeJS進行IO一個Haskell程序?

例如,我想從遠處的數據庫中獲得10條記錄,所以我想同時激發10個請求,並在結果可用時返回此集合。 IO monad不會提供幫助,因爲monad會使用bind明確地序列化計算。我認爲繼續傳遞下一個計算所需的方式會帶來同樣的問題,它會再次將計算序列化。我不想使用線程,我正在尋找另一種解決方案。這可能嗎?

+2

當你說你不想使用線程時,只要你不必自己管理它們,使用線程實現的庫是否可以接受? –

+2

你應該說什麼是你不喜歡的線程,而不僅僅是你不想使用它們。 –

+0

爲什麼要人爲排除線程?這將是Haskell的自然解決方案。 – Chuck

回答

18

哈斯克爾線程非常輕。更重要的是,GHCs IO monad在很大程度上使用事件驅動調度,這意味着普通的Haskell代碼就像繼續傳遞樣式node.js代碼(只編譯爲本機代碼並運行多個CPU ...)

您的示例是微不足道的

import Control.Concurrent.Async 

--given a list of requests 
requests :: [IO Foo] 

--you can run them concurrently 
getRequests :: IO [Foo] 
getRequests = mapConcurrently id requests 

Control.Concurrent.Async可能正是你期待的期貨圖書館。 Haskell不應該僅僅扼殺成千上萬(普通)的線程。我從來沒有寫過使用數百萬IO線程的代碼,但我猜想你唯一的問題是內存相關。

+0

我接受解決方案,但這並不能真正回答我的問題。是否有可能設計一個允許「單線程」執行無阻塞併發編程的控制結構(帶有一些底層線程池)?通過「單線程」,我的意思是確保只有一個線程正在併發執行(所有其他線程都被阻塞在等待IO),所以可以使用常規的IORefs而不進行同步/阻塞。 – mmaroti

+0

@mmaroti Hm,這樣做的一種方法是用兩個引用(用IO引用實現)和FFI動作/系統調用但通過類型系統分離成兩個Universe(不那麼難)來構建一個簡單monad,以及那麼無論何時,當你想在你的monad中用引用執行一個FFI調用時,你寫的代碼就相當於'async foo >> = unsafeInterleaveIO。等待'這會給你一個海峽兩岸的編程風格,並以異步方式執行所有IO,但具有惰性IO的所有缺點。 –

+0

嗯,我必須在此閱讀。我對惰性IO的「缺點」沒有任何問題,因爲我想要做的大部分工作都是「功能性」的:從數據庫中讀取不可變數據(例如git) – mmaroti

8

要充實對Control.Concurrent.Async的評論,以下是使用async包的示例。

import Network.HTTP.Conduit 
import Control.Concurrent.Async 

main = do 
    xs <- mapM (async . simpleHttp) [ "www.stackoverflow.com" 
            , "www.lwn.net" 
            , "www.reddit.com/r/linux_gaming"] 
    [so,lwn,lg] <- mapM wait xs 
    -- parse these how ever you'd like 

所以在上面的,我們定義了三種不同的網站3個HTTP GET請求,異步啓動這些請求,並等待所有三個在繼續之前完成。

+1

線程化代碼與單線程事件驅動不同非阻塞代碼。 (我知道nodejs在內部使用線程池,這不是重點)。您必須使用MVars在線程之間進行通信,這涉及到同步和大規模事務。但是,有了事件,我知道如果我不調用任何需要回調的任何東西,其他都不會修改程序狀態。你的解決方案使用「等待」,這將阻止,所以這種異步方法的任何調用者需要放在一個單獨的線程,以便能夠繼續:每個方法調用一個線程,不是? – mmaroti