2010-03-23 51 views
1

我有一个由文件名组成的大文件(数百个megs),每行一个。用红宝石一次读取一行文件N行

我需要遍历文件名列表,并为每个文件名分出一个进程。我一次最多需要8个分叉进程,我不想一次将整个文件名列表读入RAM。

我甚至不知道从哪里开始,任何人都可以帮助我?

+0

这个问题的标题无关与问题本身。 –

回答

4

这听起来像Process module将对此任务有用。这里的东西我赶紧扔在一起作为一个起点:

include Process 

i = 0 
for line in open('files.txt') do 
    i += 1 
    fork { `sleep #{rand} && echo "#{i} - #{line.chomp}" >> numbers.txt` } 

    if i >= 8 
     wait # join any single child process 
     i -= 1 
    end 
end 

waitall # join all remaining child processes 

输出:

 
hello 
goodbye 

test1 
test2 
a 
b 
c 
d 
e 
f 
g 
$ ruby b.rb 
$ cat numbers.txt 
1 - hello 
3 - 
2 - goodbye 
5 - test2 
6 - a 
4 - test1 
7 - b 
8 - c 
8 - d 
8 - e 
8 - f 
8 - g 

其工作原理是:

  • for line in open(XXX)会懒洋洋地遍历文件的行你指定。
  • fork会产生一个执行给定块的子进程,在这种情况下,我们使用反引号来指示要由shell执行的内容。请注意,rand在此处返回值0-1,因此我们正在睡眠不到一秒,并且我拨打line.chomp删除了我们从line得到的尾随换行符。
  • 如果我们累计了8个或更多进程,请致电wait停止一切,直到其中一个返回。
  • 最后,在循环之外,在退出脚本之前调用waitall以加入所有剩余的进程。
+0

谢谢!这看起来很有希望。我一直在用红宝石玩耍,但还没有完成“包括过程”。那是什么给你买的? – Sam

+0

没关系。我想通了:)再次感谢! – Sam

4
File.foreach("large_file").each_slice(8) do |eight_lines| 
    # eight_lines is an array containing 8 lines. 
    # at this point you can iterate over these filenames 
    # and spawn off your processes/threads 
end 
+0

这不会起作用,因为它会产生N/8个进程(N是文件中的行数)。你可以改为'each_slice(N/8)',但这需要将整个文件加载到一个数组中,这是OP想要避免的。 –

+0

我假设在循环内,OP会产生8个进程并在继续之前等待它们。我在链接可枚举的方法,所以它不会一次读取整个文件。 –

+0

啊,对不起。但是这种方式效率不高,因为程序必须等待所有八个过程才能在接下来的八个产卵之前完成,而且您将只有部分时间具有100%的流程利用率。在极端情况下,您可以快速完成七个过程,并且您必须等待一个长时间运行的左侧。 –

0

这里是马克的解决方案包裹起来作为ProcessPool类,可能是有帮助的它周围的(和请纠正我,如果我犯了一些错误):

class ProcessPool 
    def initialize pool_size 
    @pool_size = pool_size 
    @free_slots = @pool_size 
    end 

    def fork &p 
    if @free_slots == 0 
     Process.wait 
     @free_slots += 1 
    end 
    @free_slots -= 1 
    puts "Free slots: #{@free_slots}" 
    Process.fork &p 
    end 

    def waitall 
    Process.waitall 
    end 
end 

pool = ProcessPool.new 8 
for line in open('files.txt') do 
    pool.fork { Kernel.sleep rand(10); puts line.chomp } 
end 
pool.waitall 
puts 'finished' 
0

标准库文档Queue已有

require 'thread' 

queue = Queue.new 

producer = Thread.new do 
    5.times do |i| 
    sleep rand(i) # simulate expense 
    queue << i 
    puts "#{i} produced" 
    end 
end 

consumer = Thread.new do 
    5.times do |i| 
    value = queue.pop 
    sleep rand(i/2) # simulate expense 
    puts "consumed #{value}" 
    end 
end 

consumer.join 

虽然我确实发现它有点冗长。

维基百科将其描述为一个thread pool pattern

0

ARR = IO.readlines(“文件名”)