Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby线程与普通线程_Ruby_Multithreading - Fatal编程技术网

Ruby线程与普通线程

Ruby线程与普通线程,ruby,multithreading,Ruby,Multithreading,假设我有4个文件夹,每个文件夹中有25个文件夹。在这25个文件夹中,每一个都有20个文件夹,每个文件夹都有一个很长的文本文档。我现在使用的方法似乎还有改进的余地,在我实现ruby线程的每个场景中,结果都比以前慢。我有一个文件夹名称数组。我对每个文件进行迭代,并使用foreach方法来获取深度嵌套的文件。在foreach循环中,我做3件事。我得到了今天文件的内容,我得到了昨天文件的内容,我使用diff算法找到了从昨天到今天的变化。如何使用线程更快地执行此操作 def backup_differ_l

假设我有4个文件夹,每个文件夹中有25个文件夹。在这25个文件夹中,每一个都有20个文件夹,每个文件夹都有一个很长的文本文档。我现在使用的方法似乎还有改进的余地,在我实现ruby线程的每个场景中,结果都比以前慢。我有一个文件夹名称数组。我对每个文件进行迭代,并使用foreach方法来获取深度嵌套的文件。在foreach循环中,我做3件事。我得到了今天文件的内容,我得到了昨天文件的内容,我使用diff算法找到了从昨天到今天的变化。如何使用线程更快地执行此操作

def backup_differ_loop device_name

  device_name.strip!
  Dir.foreach("X:/Backups/#{device_name}/#{@today}").each do |backup|

    if backup != "." and backup != ".."
      @today_filename = "X:/Backups/#{device_name}/#{@today}/#{backup}"
      @yesterday_filename = "X:/Backups/#{device_name}/#{@yesterday}/#{backup.gsub(@today, @yesterday)}"

      if File.exists?(@yesterday_filename)
        today_backup_content = File.open(@today_filename, "r").read
        yesterday_backup_content = File.open(@yesterday_filename, "r").read

        begin
         Diffy::Diff.new(yesterday_backup_content, today_backup_content, :include_plus_and_minus_in_html => true, :context => 1).to_s(:html)
        rescue
         #do nothing just continue
        end

        end

      else
       #file not found
      end

    end

  end

逻辑的第一部分是查找特定文件夹中的所有文件。不必执行Dir.foreach,然后检查“.”和“.”。您可以在一行中执行此操作:

files = Dir.glob("X:/Backups/#{device_name}/#{@today}/*").select { |item| File.file?(item)}
注意结尾的
/*
?这将搜索1级深度(在@today文件夹中)。如果您也想在子文件夹内搜索,请将其替换为
/***
,这样您将获得@today的所有子文件夹内的所有文件数组

所以我首先有一个方法,它会给我一个双数组,包含一组匹配文件的数组:

def get_matching_files
  matching_files = []

  Dir.glob("X:/Backups/#{device_name}/#{@today}/*").select { |item| File.file?(item)}.each do |backup|
    today_filename = File.absolute_path(backup) # should get you X:/Backups...converts to an absolute path
    yesterday_filename = "X:/Backups/#{device_name}/#{@yesterday}/#{backup.gsub(@today, @yesterday)}"

    if File.exists?(yesterday_filename)
      matching_files << [today_filename, yesterday_filename]
    end
  end

  return matching_files
end
现在我们可以开始多线程,这可能会减慢速度。我首先将数组中与_文件匹配的所有文件放入一个队列,然后启动5个线程,直到队列为空:

queue = Queue.new
matching_files.each { |file| queue << file }

# 5 being the number of threads
5.times.map do
  Thread.new do
    until queue.empty?
      begin
        today_file_content, yesterday_file_content = queue.pop
        Diffy::Diff.new(yesterday_backup_content, today_backup_content, :include_plus_and_minus_in_html => true, :context => 1).to_s(:html)
      rescue
        #do nothing just continue
      end
    end
  end
end.each(&:join)
queue=queue.new
将_files.each{| file | queue true,:context=>1.to _s(:html)
营救
#什么都不做,继续
结束
结束
结束
结束。每个(&:连接)
我不能保证我的代码能工作,因为我没有你程序的全部上下文。我希望我已经给了你一些想法


最重要的是:Ruby的标准实现一次只能运行一个线程。这意味着即使您实现了上述代码,您也不会获得显著的性能差异。因此,请使用Rubinius或JRuby,它们允许一次运行多个线程。或者,如果您更喜欢使用标准的MRI Ruby,那么您需要要重新构造代码(您可以保留原始版本)并启动多个进程,您只需要一个共享数据库之类的东西,可以在其中存储匹配的_文件(例如,作为一行)每次进程从该数据库中“获取”某些内容时,它都会将该行标记为“已使用”。我认为SQLite是一个很好的数据库,因为默认情况下它是线程安全的。

大多数Ruby实现没有“true”多核线程(即线程)不会为您带来任何性能改进,因为解释器一次只能运行一个线程。对于像您这样具有大量磁盘IO的应用程序,这一点尤其正确。事实上,即使使用真正的多线程,您的应用程序也可能受到IO限制,仍然看不到多大的改进


通过在代码中找到一些低效的算法并加以改进,您更有可能获得结果。

线程的简单版本是使用池来处理每个文件(甚至是目录/设备,具体取决于作用域)在单独的线程中作为单个独立进程。池允许单个线程(一次一个)处理多个项目,从而避免了一点开销。如果没有修改的共享数据(即“备份”对于每个线程进程都是唯一的),则无需担心并发问题(启动它除外)。此外,Ruby的版本对这是否是一个有益的改变也很重要。现在去阅读并设计一个实现。回来时会遇到一个问题:)每个文件都有2个不同的文件内容。因此,当你循环和创建线程时,你从哪里获得内容?如果你想知道,你如何确定哪一个是今天和昨天您是否使用队列?您首先将它们配对在一个数组中,这样您将得到一个包含一组这些对的双数组。队列本身就是双数组,每个queue.pop将得到一个包含两个项的单个数组元素,因此并行赋值。
queue = Queue.new
matching_files.each { |file| queue << file }

# 5 being the number of threads
5.times.map do
  Thread.new do
    until queue.empty?
      begin
        today_file_content, yesterday_file_content = queue.pop
        Diffy::Diff.new(yesterday_backup_content, today_backup_content, :include_plus_and_minus_in_html => true, :context => 1).to_s(:html)
      rescue
        #do nothing just continue
      end
    end
  end
end.each(&:join)