Я хочу создать такую систему, чтобы пользователи могли отправлять файлы. После отправки файла я запустил некоторые скрипты с файлами. Я хочу запустить эти файлы в порядке, поэтому я хочу поддерживать очередь запросов. Как я могу это сделать с помощью php? Есть ли для этого библиотека с открытым исходным кодом?
Благодарю!
Третья библиотека? Слишком просто нужна целая библиотека. Вы можете использовать Redis (см. Ответ AlanChavez), если вы хотите тратить время и ресурсы, а затем должны быть обеспокоены сбором мусора, когда реальное решение заключается не в том, чтобы вначале вносить мусор в микс.
Ваша очередь - текстовый файл. Когда файл загружается, имя файла добавляется в очередь.
$q= fopen('queue.txt','a');
'a'
режим 'a'
. Он автоматически перемещает указатель записи в конец файла для добавления записей. Но причина в том, что это важно, потому что, если файл не существует, создается новый.
fwrite($q,"$filename\n");
fclose($q);
Если одновременный файл append записывает в этот файл, OS может разрешить конфликт без ошибок. Нет необходимости в блокировке файлов, совместной многозадачности или транзакционной обработке.
Когда ваш скрипт, который обрабатывает очередь, начинает запускать, он переименовывает прямую очередь в рабочую очередь.
if(!file_exists('q.txt')){
if(!file_exists('queue.txt')){exit;}
rename('queue.txt','q.txt');
$q = fopen('q.txt','r');
while (($filename = fgets($q, 4096)) !== false) {
process($filename);
}
fclose($q);
unlink('q.txt');
}
else{
echo 'Houston, we have a problem';
}
Теперь вы видите, почему важен режим 'a'
. Мы переименовываем очередь, и когда происходит следующая загрузка, автоматически создается файл queue.txt.
Если файл записывается, поскольку он переименовывается, ОС будет сортировать его без ошибок. Переименование происходит настолько быстро, что вероятность одновременной записи астрономически мала. И это основная функция ОС, чтобы разобраться в конкуренции файловой системы. Нет необходимости в блокировке файлов, совместной многозадачности или транзакционной обработке.
Это пуленепробиваемый метод, который я использую в течение многих лет.
Замените цитату Apollo 13 процедурой восстановления ошибок. Если q.txt существует, предыдущая обработка не завершилась успешно.
Это было слишком легко.
Потому что это так просто, и у нас много памяти, потому что мы настолько эффективны: пусть будет весело.
Посмотрим, будет ли запись в очередь быстрее, чем AlanChavez "супер быстрый" Redis с его единственным двузначным миллисекундным ответом.
Время в секундах, чтобы добавить имя файла в очередь = 0.000014537 или 14.5μS. Чуть лучше, чем Redis "супер быстрый" 10-99 мс Время отклика, как минимум, 100 000%.
Я бы использовал Редис. Redis - супербыстрое хранилище ключей; обычно его время отклика - это двузначные микросекунды. (10 - 99 мкс)
Операции Redis являются атомарными (транзакции либо происходят, либо нет), и вы можете постоянно работать, не используя cron.
Чтобы использовать Redis с PHP, вы можете использовать Predis.
После того, как redis установлен, и Predis настроен для работы с вашим скриптом, при загрузке файла я бы сделал что-то вроде этого:
// 'hostname' and 'port' is the hostname and the port
// where Redis is installed and listening to.
$client = new Predis\Client('tcp://hostname:port');
// assuming the path to the file is stored in $pathToFile
$client->lpush('queue:files', $pathToFile);
то скрипт, который должен работать с файлами, просто нужно сделать что-то вроде:
$client = new Predis\Client('tcp://hostname:port');
// assuming the path to the file is stored in $pathToFile
while(true){
$pathToFile = $client->rpop('queue:files');
if(!$pathToFile) {
// list is empty, so move on.
continue;
}
// there was something in the list, do whatever you need to do with it.
// if there an exception or an error, you can always use break; or exit; to terminate the loop.
}
Учитывайте, что PHP имеет тенденцию использовать много памяти, поэтому я бы либо явно собирал мусор (через gc_enable()
и gc_collect_cycles()
и unset()
переменные, как вы идете).
Кроме того, вы можете использовать программное обеспечение, такое как supervisord
чтобы запустить этот скрипт один раз, и как только он закончится, запустите его снова.
В общем, я бы держался подальше от использования базы данных и cron для реализации очередей. Это может привести к серьезным проблемам.
Предположим, например, что вы используете таблицу в качестве очереди.
В первом запуске ваш скрипт вытаскивает задание из базы данных и начинает делать что-то.
Затем по какой-то причине ваш сценарий занимает больше времени, и работа cron снова запускается, и теперь у вас есть 2 скрипта, работающих с одним и тем же файлом. Это может либо не иметь последствий, либо может иметь серьезные последствия. Это зависит от того, что делает ваше приложение.
Поэтому, если вы не работаете с очень маленьким набором данных, и вы точно знаете, что ваш cronjob закончит до того, как будет запущен предыдущий скрипт, и не будет никаких столкновений, тогда вам все будет в порядке. В противном случае, избегайте этого подхода.
continue;
с break;
, «Примите во внимание, что PHP имеет тенденцию использовать много памяти»? Ну, может быть, если вы собираетесь внести ненужный мусор в смесь. Вы думаете, 10-99 мс "супер быстро"? «Это может привести к серьезным проблемам». ??? Если вы пишете плохой код. Я собираюсь догадаться, что вы - тот, за кого проголосовали @JohnnyFaldo. Его -2 очка пришли примерно 20 февраля в 17:07? Его ответ лучше твоего. Это ужасный ответ. Смотри мой ответ
Я бы использовал базу данных.
FILE, QUEUE_ORDER