我有一个由文件名组成的大文件(数百个megs),每行一个。用红宝石一次读取一行文件N行
我需要遍历文件名列表,并为每个文件名分出一个进程。我一次最多需要8个分叉进程,我不想一次将整个文件名列表读入RAM。
我甚至不知道从哪里开始,任何人都可以帮助我?
我有一个由文件名组成的大文件(数百个megs),每行一个。用红宝石一次读取一行文件N行
我需要遍历文件名列表,并为每个文件名分出一个进程。我一次最多需要8个分叉进程,我不想一次将整个文件名列表读入RAM。
我甚至不知道从哪里开始,任何人都可以帮助我?
这听起来像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
其工作原理是:
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
这不会起作用,因为它会产生N/8个进程(N是文件中的行数)。你可以改为'each_slice(N/8)',但这需要将整个文件加载到一个数组中,这是OP想要避免的。 –
我假设在循环内,OP会产生8个进程并在继续之前等待它们。我在链接可枚举的方法,所以它不会一次读取整个文件。 –
啊,对不起。但是这种方式效率不高,因为程序必须等待所有八个过程才能在接下来的八个产卵之前完成,而且您将只有部分时间具有100%的流程利用率。在极端情况下,您可以快速完成七个过程,并且您必须等待一个长时间运行的左侧。 –
这里是马克的解决方案包裹起来作为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'
标准库文档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
ARR = IO.readlines(“文件名”)
这个问题的标题无关与问题本身。 –