2010-03-23 80 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(「文件名」)