2011-10-24 4 views
1

Для проекта, над которым я работал, мне нужна очередь, которая будет слишком большой для хранения в обычной памяти. Я реализовал его как простой файл, где он читал весь файл, забирал первые несколько (~ 100) строк, обрабатывал их, а затем записывал обновленную очередь с новыми добавленными инструкциями и удалял старые. Однако, поскольку очередь стала слишком большой для хранения в памяти, мне нужно что-то другое. Предпочтительно, кто-то может сказать мне способ очистить только первые несколько строк файла, не глядя на остальные данные. Я думал об использовании базы данных (MySQL, вероятно, с отсортированными временными метками вставки), но я бы предпочел сделать это без объяснения причин загрузки и пропускной способности (несколько серверов должны были бы отправлять и получать много данных из БД). Язык, на котором я работаю, - это PHP, но на самом деле этот вопрос больше касается файлов unix, я полагаю. Любая помощь будет оценена по достоинству.Реализация файла очереди PHP

+3

«* несколько серверов должны будут отправлять и получать много данных из БД *». Это именно то, для чего предназначены серверы баз данных (и оптимизированы). – qJake

+0

Я знаю, что база данных может справиться с этим, но меня больше беспокоит пропускная способность, связанная с постоянным запуском этого процесса и съемкой данных между всеми моими серверами ... Путь MySQL - это мое последнее средство, но мне бы очень хотелось, чтобы кто-то знает способ обновления файла для удаления первых нескольких строк без необходимости просмотра всех данных. – hackartist

ответ

1

Сосать первую строку файла довольно тривиально (fopen(), а затем fgets()). Повторная запись файла для удаления завершенных заданий будет очень болезненной, особенно если у вас есть несколько параллельных серверов, работающих с одним и тем же файлом очереди.

Один из вариантов - использовать отдельный файл для каждого задания. Если у вас есть метод параллельной работы для генерации инкрементирующего идентификатора для этих файлов, то было бы просто выбрать файл с наименьшим идентификатором для самого старого задания и создать новый идентификатор для каждого нового задания. Однако вам придется разобраться в блокировке файлов, однако, чтобы одновременно сохранить два + сервера, захватывающих один и тот же файл.

+0

Я действительно использую блокировку - мне действительно нужен какой-то способ перемещения указателя, который означает начало файла вниз по уже выполненным строкам. – hackartist

+0

вы можете использовать 'ftell()', чтобы получить позицию маркера 'start here' в файле очереди и сохранить это в отдельном файле. lock/read/update/write/unlock на небольшом ~ 10-байтовом файле будет довольно быстрым, и вы сможете легко прокручивать его прямо в нужное место в очереди. –

+0

ok, который больше похож на то, что я ищу ... фактический размер файла очереди будет продолжать расти, поэтому я должен в какой-то момент выпустить его из одного объема памяти размером с один раз ... – 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.

Смежные вопросы