2011-10-24 112 views
1

對於我正在研究的項目,我需要一個隊列,這個隊列太大而無法保存在正常的內存中。我一直在實現它作爲一個簡單的文件,它將讀取前幾個(〜100)行的整個文件,處理它們,然後寫入更新的隊列,並添加新指令並刪除舊指令。但是,由於隊列變得太大而不能像這樣保持記憶,所以我需要不同的東西。最好有人可以告訴我一種方法來剝離文件的前幾行而不必查看其餘數據。我曾考慮過使用數據庫(MySQL可能帶有排序的插入時間戳),但是我更願意在沒有負載和帶寬的情況下執行它(幾個服務器都必須從DB發送和接收大量數據)。我正在使用的語言是PHP,但真的這個問題更多的是關於unix文件,我想。任何幫助,將不勝感激。PHP隊列文件執行

+3

「*幾臺服務器都必須從DB *發送和接收大量數據*」 - 這正是數據庫服務器設計(和優化)的功能。 – qJake

+0

我知道數據庫可以處理它,但是我更關心的是帶寬使得這個過程不斷運行,並在我所有的服務器之間拍攝數據...... MySQL的方式是我的最後一招,但我真的更喜歡如果有人知道一種方法來更新文件以刪除前幾行而不必查看所有數據。 – hackartist

回答

1

吸出文件的第一行非常微不足道(fopen()後跟fgets())。重新寫入文件以刪除完成的作業將會非常痛苦,特別是如果您有多個併發服務器在同一個隊列文件中工作。

另一種方法是對每個作業使用一個單獨的文件。如果您有一些爲這些文件生成增量ID的併發安全方法,那麼挑選最舊作業的ID最低的文件併爲每個新作業生成一個新ID會很簡單。不過,你必須弄清楚一些文件鎖定,讓兩臺服務器同時抓取同一個文件。

+0

我實際上正在使用鎖定 - 我真正需要的是某種方式來移動指針,該指針表示文件的起始位置已經被執行。 – hackartist

+0

您可以使用'ftell()'獲取隊列文件中「start here」標記的位置,並將其存儲在單獨的文件中。鎖定/讀取/更新/寫入/解鎖一個小的~10字節的文件會很快,並讓您直接滾動到隊列中的相關位置。 –

+0

好吧,聽起來更像我正在尋找的...隊列文件的實際大小將繼續增長,所以我不得不在某個時刻清空它一次一個內存大小的塊... – hackartist

0

我在處理enqueue/fs運輸時遇到同樣的問題。我沒有在文件開始時修改一小部分文件,也沒有將它複製到內存並保存回去。相反,但可以在文件結尾處做到這一點。你可以閱讀一部分,然後截斷它。這不是一個真正的隊列,而是一個堆棧。所以如果你依靠消息排序,這不會是一個解決方案。在我的情況下,我從文件中讀取文件時鎖定文件,鎖定被釋放。

這是你怎麼能寫消息隊列文件:

<?php 
$rawMessage = 'this your message to put to the queue as a string'; 

$queueFile = fopen('/path/to/queue/file', '+a'); 

// here it may add some spaces so the message length is multiples of modular. 
// that make it easier to read messages from a file. 

// lock file 

$rawMessage = str_repeat(' ', 64 - (strlen($rawMessage) % 64)).$rawMessage; 
fwrite($queueFile, $rawMessage); 

// release lock 

這是你如何可以讀取隊列文件的消息:

<?php 

$queueFile = fopen('/path/to/queue/file', '+c'); 

// lock file 

$frame = readFrame($file, 1); 
ftruncate($file, fstat($file)['size'] - strlen($frame)); 
rewind($file); 
$rawMessage = substr(trim($frame), 1); 

// release lock 


function readFrame($file, $frameNumber) 
{ 
    $frameSize = 64; 
    $offset = $frameNumber * $frameSize; 
    fseek($file, -$offset, SEEK_END); 
    $frame = fread($file, $frameSize); 
    if ('' == $frame) { 
     return ''; 
    } 
    if (false !== strpos($frame, '|{')) { 
     return $frame; 
    } 
    return readFrame($file, $frameNumber + 1).$frame; 
} 

對於鎖定我建議使用Symfony LockHandler或簡單地採取enqueue/fs。