【问题标题】:Threading in Ruby with a limitRuby 中的线程有限制
【发布时间】:2010-12-14 10:14:38
【问题描述】:

我有一个任务需要执行,do_stuff(opts),每个任务需要大约 1 秒,即使其中 1 到 10 个并行运行。最后我需要为每个操作收集一个结果数组。

如果我有 30 件事情要做,我将如何有效地使用线程来排队 do_stuff(opts) 操作,因此不超过 10 个同时运行,但结果数组直到全部(30 ) 任务完成了吗?

我通常至少有一些代码来尝试说明我的意思,但是对于线程,我有点不知所措!提前致谢

【问题讨论】:

    标签: ruby multithreading queue


    【解决方案1】:

    另外,如果您不熟悉 Ruby 线程,请查看 this 教程。

    【讨论】:

    • 您的链接似乎已失效。哪里有副本?
    • @Naremy,我已经修复了链接。有空请点赞。
    • 我不是反对者,但如果我能让你开心的话;)
    【解决方案2】:

    我使用paralsparalsmap

    def parals(objects, n: 50)
      objects.shuffle.each_slice(n).map do |g|
        print '{'
        threads = []
        g.map { |i| threads << Thread.new(i) { |i| yield(i) } }
        threads.each(&:join)
        print '}'
      end
    end
    
    def paralsmap(objects, n: 50)
      res = []
    
      objects.each_slice(n).map do |g|
        print '{'
        threads = []
        g.map { |i| threads << Thread.new(i, res) { |i| res << yield(i) } }
        threads.each(&:join)
        print '}'
      end
    
      res
    end
    

    例如:

    parals((0..100).to_a) { |i| puts i }
    urls = parals((0..100).to_a) { |i| "https://google.com/?q=#{i}" }
    

    可以使用n参数来限制线程数。

    【讨论】:

      【解决方案3】:

      此解决方案将结果收集在 $results 数组中。它允许创建“thread_limit”线程,然后等待它们完成后再创建。

         $results = []
      
         def do_stuff(opts={})
           'done'
         end
      
         def thread_wait(threads)
           threads.each{|t| t.join}
           threads.each {|t| $results << t }
           threads.delete_if {|t| t.status == false}
           threads.delete_if {|t| t.status.nil? }
         end
      
         opts = {}
         thread_limit = 20
         threads = []
         records.each do |r|
           thread_wait(threads) while threads.length >= thread_limit
           t = Thread.new { do_stuff(opts) }
           t.abort_on_exception = true
           threads << t
         end
         # Ensure remaining threads complete
         threads.each{|t| t.join}
      

      【讨论】:

        【解决方案4】:

        我不知道它对于更复杂的应用程序的效果如何,但我发现这样的东西可以很好地用于 macruby 的简单线程场景。

        thread_limit = 4
        
        threads = []
        things_to_process.each do |thing|
          until threads.map { |t| t.status }.count("run") < thread_limit do sleep 5 end
          threads << Thread.new { the_task(thing) }
        end
        output = threads.map { |t| t.value }
        

        直到循环等待,直到创建的线程数少于指定数量,然后才允许主线程继续执行以启动下一个线程。

        输出变量将被分配一个由 the_task 返回的值组成的数组,其顺序对应于输入数组things_to_process。主线程将阻塞,直到每个创建的线程都返回一个值。

        【讨论】:

        • 我使用 thread.alive 会更好吗?而不是状态:threads.map {|t| t.alive?}.count(true)
        【解决方案5】:

        如果您真的很追求性能,您可能还想查看jruby
        它使用实际的操作系统线程,而不是其他 ruby​​ 实现使用的绿色线程

        【讨论】:

          【解决方案6】:

          您需要实现 this pattern
          This question 讨论如何在 Ruby 中完成此操作

          【讨论】:

            猜你喜欢
            • 2011-09-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多