【问题标题】:Does Ruby have any construct similar to Clojure's pmap for parallel processing?Ruby 是否有任何类似于 Clojure 的 pmap 用于并行处理的构造?
【发布时间】:2011-02-16 16:37:21
【问题描述】:

我正在尝试决定是用 Ruby 还是 Clojure 实现应用程序。其中两个要求涉及并行处理:

  1. 应用程序必须进行并行调用以通过 Internet 获取 XML 提要和其他类型的数据。进行了许多这样的调用,并且将调用序列化是低效的。

  2. 理想情况下,对这些调用的响应应该并行处理。处理主要意味着将原始 XML 转换为更小的结构化数据(Ruby 哈希或 Clojure 映射)并将其插入 MySQL 数据库或 CouchDB 数据库。

我比 Clojure 更了解 Ruby,但如果这是适合 Clojure 的项目,我完全赞成使用它。

Clojure 的pmap 函数似乎非常适合这两个要求。我想知道是否某些 Ruby 库或功能具有类似的干净和简单的方法来执行上述并行处理任务。

【问题讨论】:

  • 另外,有谁知道 pmap 是否会阻止太多线程同时产生和运行?
  • @dan pmap 具有某种“半惰性的速率控制,因为并行计算保持领先于消耗,但除非需要,否则不会实现整个结果”(clojure docs
  • 好吧,有点含糊但很有用
  • @dan:从源代码中,我看到它一次最多运行(+ 2 (.. Runtime getRuntime availableProcessors)) 个线程,并且仅在您需要它们时计算更多。 (我不完全了解内部结构,因为我一般不懂语言。)
  • @Andrew:MRI 使用绿色线程并且一次只使用一个处理器。 YARV 使用 Posix 线程,但有一个全局解释器锁,可以消除(几乎?)所有并发性。但是,当目标是在等待阻塞 I/O 时执行其他操作时,线程在两个解释器中都可以很好地工作,就像这里的情况一样。 (我以前做过。)

标签: ruby clojure


【解决方案1】:

使pmap 函数可重用同样简单:

module Enumerable
  def pmap
    map {|x| Thread.start {yield x}}.map {|t| t.join.value}
  end
end

但是,当然,使用适当的线程池/执行器可能是个好主意。这里是an example

【讨论】:

  • 请注意,eigenclass 线程池没有任何简单的方法来获取线程的返回值。
  • @tokland: *args 无论如何都只会包含一项。
  • @Ken。为什么块应该只有一个参数?
  • @tokland, map 一次将一个元素传递给块。为什么你会期望有不止一个论点?
  • @Ken:我在想这样的事情:[[1, 2], [2, 3], [4, 5]].pmap { |x, y| x + y } # => [3, 5, 9]。但显然 yield([1,2]) 在块参数 |x, y| 中被扩展,这让我感到惊讶,我希望 x 中的完整对。
【解决方案2】:

这是一个简单的小例子,说明了一种方法。请注意,它一次创建的线程数量没有任何限制,因此如果您运行大量线程,您可能需要创建某种线程池。

[1,2,3].map{|x| Thread.start{x+1}}.map{|t| t.join.value}

【讨论】:

    【解决方案3】:

    我认为实现语言的选择取决于您的应用程序。

    如果您受网络限制,Ruby 应该可以正常工作。您可能会发现使用reactor patternEventMachine 来实现并发请求更容易。您可以使用 EventMachine::Protocols::HttpClient 类发出 HTTP 请求。

    EventMachine.run {
       http = EventMachine::Protocols::HttpClient.request(
         :host => server,
         :port => 80,
         :request => "/index.xml"
       )
       http.callback {|response|
         # process response
       }
     }
    

    这样您无需担心并发性和所有相关的复杂性,但您将获得高吞吐量,因为您可以发出大量并发请求。

    如果您受 CPU 限制,这将不起作用。如果您将大部分时间用于处理 XML 提要,而不是等待 I/O 来获取提要或插入数据库,那么您将不得不在 JRuby 上运行 Ruby 或运行多个 Ruby 进程以实现良好的多核利用率。

    在 CPU 受限的情况下,我会使用 Clojure,因为如果你真的是 CPU 受限,那么在 Clojure 中进行处理将更容易进行并行处理,而且速度更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-14
      • 1970-01-01
      • 2013-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多