我想设计一个用户可以提交文件的系统。在他们提交文件后,我会用这些文件运行一些脚本。我想按顺序运行这些文件,所以我想维护一个请求队列。如何使用php实现这一点?有开源库吗?
谢谢!
我会使用数据库。。
- 当用户提交一个文件时,它会向数据库添加一个指向该文件在文件系统中位置的链接
- 您有一个运行的cron,它检查新提交并按顺序处理它们,完成后会在数据库中将其标记为已处理
我会使用Redis。Redis是一个超高速的键值存储;通常它的响应时间是两位数微秒。(10-99微秒)
Redis事务是原子性的(事务要么发生,要么不发生),您可以在不使用cron的情况下让作业不断运行。
要在PHP中使用Redis,您可以使用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's 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作业再次启动,现在您有两个脚本在同一个文件中工作。这可能没有任何后果,也可能产生严重后果。这取决于您的应用程序实际在做什么。
因此,除非您使用的是一个非常小的数据集,并且您确信您的cronjob将在上一个脚本运行之前完成,并且不会发生冲突,否则您应该没事。否则,请远离这种方法。
第三方库?太简单了,不需要一个完整的图书馆。如果你想浪费时间和资源,然后又不得不关心垃圾收集,那么你可以使用Redis(见AlanSavez的回答),而真正的解决方案是一开始就不把垃圾带入垃圾中
您的队列是一个文本文件。上传文件时,文件名会附加到队列中
$q= fopen('queue.txt','a');
'a'
模式很重要。它会自动将写入指针移动到文件末尾以进行追加写入。但它之所以重要,是因为如果文件不存在,就会创建一个新文件
fwrite($q,"$filename'n");
fclose($q);
如果同时对该文件进行追加写入,则操作系统会无错误地仲裁冲突。无需文件锁定、协作多任务处理或事务处理
当处理队列的脚本开始运行时,它会将活动队列重命名为工作队列
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存在,则先前的处理未成功完成
这太容易了
因为它很简单,我们有足够的记忆力,因为我们效率很高:让我们玩得开心
让我们看看写入队列是否比AlanSavez的"超快"Redis(只有两位数的毫秒响应)更快
将文件名添加到队列的时间(以秒为单位)=0.000014537或14.5µS。比Redis的"超快"10-99 mS响应时间至少好100000%