道歉,如果之前已经涵盖过 - 我进行了搜索,但可能不知道使用的正确术语。
此过程由PHP处理。
情况如下:
我有大量的文件名。我打开的脚本打开这些文件并将其内容输入数据库。一次处理这些文件需要24小时,这些文件每天都会更新。
将单个大型数组拆分为四个较小的数组并运行并发进程在24小时窗口结束之前完成作业,但有时一个或两个进程将在其他进程之前完成数小时,因为文件大小每天都在变化。
就像那些存放零售货架的人(之前曾经做过那个噩梦的人?)在完成自己的任务后帮忙解决剩下的问题,我想在这些“代理人”做的地方有一个脚本同样的。
以下是我所知道的一些基础知识 - 这可能是错的,如果我是,我也不会自豪地抗议: - )
$files = array('file1','file2','file3','file4','file5');
//etc... on to over 4k elements
while($file = array_pop($files)){
//Something in here... I have no idea what.
}
想法?有一些像四个函数调用或者四个循环的东西已经超出了我的想法,但是我很确定它会等到执行后续调用,直到前一个完成。
感谢任何帮助。我非常认真地坚持这个!
谢谢!
答案 0 :(得分:2)
你想要的是什么叫做“消息队列”。像beanstalkd
这样的东西您基本上会创建一个包含各个文件名的邮件列表。然后,您将创建一组处理器来处理它们。每个处理器将处理一个文件,然后返回队列以查看是否有更多消息/文件等待处理。
编辑: 这是一个类比,以帮助解释消息队列。你的第一个想法就像是一个人工经理拿着一堆文件,把它们分成四堆,然后将他的四个员工中的每一个交给他们处理。消息队列更像是这样:管理器将所有文件放在一个表上,并告诉每个员工从表中获取一个文件并对其进行处理。他告诉他们,当他们完成第一个文件以继续获取文件,直到桌面上没有更多文件。完成所有文件后,员工可以回家。
一名员工最终可能会使用非常大的文件而只处理一些文件,而另一名员工可能会获得较小的文件并处理许多文件。每个员工处理的数量无关紧要,他们都会继续工作直到桌子为空。
答案 1 :(得分:2)
数据库支持的消息队列似乎是一个明显的解决方案,但我认为在这种情况下这样做太过分了。我只是将要处理的文件放入一个专用的队列目录中,然后使用DirectoryIterator类进行扫描。像这样:
while (true) {
look in the queue directory for a file
if you don't fine one, exit the script, all processing is done
if you find one, rename it or move it to a work directory
if the rename/move command succeeded, process the file
if the rename/move command failed, one of the other threads got it first
}
编辑:
关于启动worker,你可以使用一个简单的shell脚本在后台生成PHP进程:
NUM_WORKERS=5
for WORKER in $(seq 1 ${NUM_WORKERS})
do
echo "starting worker ${WORKER}"
php -f /path/to/my/process.php &
done
然后,创建一个cron条目来运行此启动器,例如,在午夜:
0 0 * * * /path/to/launcher.sh
答案 2 :(得分:1)
我会有一个套接字服务器主脚本,它将文件路径分发给x个从属脚本,直到没有剩下的文件要处理。这样,所有从属脚本都将继续运行,您可以根据请求动态分发文件路径。
这样的事情:
<强> master.php 强>
<?php
// load the array of files to process (however you do this)
$fileList = file('filelist.txt');
// Create a listening socket on localhost
$serverSocket = stream_socket_server('tcp://127.0.0.1:7878');
$sockets = array($serverSocket);
$clients = array();
// Loop while there are still files to process
while (count($fileList)) {
// Run a select() call on the existing sockets' read buffers
// Skip to next iteration if no sockets are waiting for handling
if (stream_select($read = $sockets, $write = NULL, $except = NULL, 1) < 1) {
continue;
}
// Loop sockets with data to read
foreach ($read as $socket) {
if ($socket == $serverSocket) {
// Accept new clients
$sockets[] = $clients[] = stream_socket_accept($serverSocket);
} else if (trim(fgets($socket)) == 'next') {
// Hand out a new file path to the client
fwrite($socket, array_shift($fileList)."\n");
if (!count($fileList)) {
break 2;
}
}
}
}
// When we're done, disconnect the clients
foreach ($clients as $socket) {
@fclose($socket);
}
// ...and close the listen socket
@fclose($serverSocket);
<强> slave.php 强>
<?php
$socket = fsockopen('127.0.0.1', 7878);
while (!feof($socket)) {
// Get a new file path from the master
fwrite($socket,"next\n");
$path = trim(fgets($socket));
if (is_file($path)) {
// Process the file at $path here
}
}
然后你需要启动 master.php ,然后当它运行时,你可以根据需要启动很多 slave.php 的实例,他们会所有都继续运行,直到没有更多文件要处理。
显然,这没有错误处理,但它应该提供一个基本框架来帮助您入门。这依赖于阻止函数调用(stream_select()
和fgets()
)以避免竞争条件 - 这可能会或可能不足以满足您的目的。