【问题标题】:Non-blocking IO with Haskell [duplicate]使用 Haskell 进行非阻塞 IO [重复]
【发布时间】:2012-11-28 11:14:48
【问题描述】:

可能重复:
What is the Haskell response to Node.js?
How can I watch multiple files/socket to become readable/writable in Haskell?

是否可以编写一个像 nodejs 那样以非阻塞方式执行 IO 的 Haskell 程序?

例如,我想从一个很远的数据库中获取 10 条记录,所以我想同时触发 10 个请求,当结果可用时,然后返回这个集合。 IO monad 不会有帮助,因为 monad 使用 bind 显式序列化计算。我认为你传递接下来想要的计算的延续传递风格有同样的问题,它再次序列化计算。我不想使用线程,我正在寻找另一种解决方案。这可能吗?

【问题讨论】:

  • 当您说您不想使用线程时,是否可以使用通过线程实现的库,只要您不必自己管理它们?
  • 你应该说出你不喜欢的线程是什么,而不仅仅是你不想使用它们。
  • (我应该指出,与 OS 线程相比,Haskell 对线程的处理非常轻量级,这也是现有 Web 服务器框架可以很好扩展的原因之一。)
  • 5 秒的谷歌搜索提示我 node.js 的非阻塞操作是使用线程实现的。所以如果你想实现类似的东西,你需要线程参与。
  • @mmaroti 对,我想这可能是你的抱怨。 Haskell 线程可以扩展到数十万个范围,所以只需使用它们! (这也是我提出另一个 StackOverflow 问题的原因,它和你有同样的担忧。)

标签: node.js haskell nonblocking continuation-passing


【解决方案1】:

Haskell 线程的重量非常轻。更重要的是,GHC 的 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 线程的代码,但我猜你唯一的问题是与内存相关的。

【讨论】:

  • 我接受解决方案,但这并不能真正回答我的问题。是否可以设计一种控制结构,允许“单线程”执行非阻塞并发编程(使用一些底层线程池)? “单线程”是指确保只有一个线程同时执行(所有其他线程都被阻塞等待 IO),因此可以使用没有同步/阻塞的常规 IORef。
  • @mmaroti 嗯,这样做的一种方法是构建一个简单的 monad,其中包含引用(用 IO refs 实现)和 FFI 操作/系统调用,但由类型系统(不是很难做到),然后任何时候你想在你的 monad 中使用引用执行 FFI 调用,你编写的代码相当于 async foo >>= unsafeInterleaveIO . wait 这会给你一个严格的编程风格,并在一个异步方式,但具有惰性 IO 的所有缺点。
  • 嗯,我必须阅读这个。我对惰性 IO 的“缺点”没有意见,因为我想做的大部分是“功能性”:从数据库(例如 git)读取不可变数据
【解决方案2】:

要充实 Control.Concurrent.Async 上的 cmets,这里是使用 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

所以在上面我们为三个不同的网站定义了三个 HTTP get 请求,异步启动这些请求,并等待所有三个完成后再继续。

【讨论】:

  • 线程代码与单线程事件驱动的非阻塞代码不同。 (我知道 nodejs 在内部使用线程池,这不是重点)。您必须使用 MVar 在线程之间进行通信,这涉及同步和更大规模的事务。但是,对于事件,我知道如果我不调用任何需要回调的东西,那么没有其他东西会修改程序状态。您的解决方案使用“等待”,这将阻塞,因此此类异步方法的任何调用者都需要放在单独的线程中才能继续:每个方法调用一个线程,不是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-15
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 1970-01-01
相关资源
最近更新 更多