Cli*_*ote 2 php mysql performance multithreading
我有一个需要处理的数据列表.它现在的工作方式是这样的:
这需要太长时间.我想要的是:
这样的事情可能吗?
我以为我每秒都使用CRON来启动脚本实例.所有需要处理的项目都将在MySQL数据库中进行标记,因此每当通过CRON启动实例时,它只会将标记的下一个项目处理并删除该标志.
思考?
编辑:为了澄清一些事情,每个'item'作为单独的行存储在mysql数据库表中.每当处理项开始处理时,它都被标记为在db中处理,因此每个新实例将只抓取未处理的下一行并处理它.因此,我不必将这些项目作为命令行参数提供.
这是一个解决方案,而不是最好的解决方案,但在Linux上运行良好:
将处理PHP拆分为单独的CLI脚本,其中:
您的主脚本(可能在您的网络服务器上)会:
后台nohup启动的应用程序将独立于启动它的脚本运行.
这让我很感兴趣,我决定写一个POC.
test.php的
<?php
$dir = realpath(dirname(__FILE__));
$start = time();
// Time in seconds after which we give up and kill everything
$timeout = 25;
// The unique identifier for the request
$id = uniqid();
// Our "items" which would be supplied by the user
$items = array("foo", "bar", "0xdeadbeef");
// We exec a nohup command that is backgrounded which returns immediately
foreach ($items as $item) {
exec("nohup php proc.php $id $item > $dir/proc.$id.$item.out &");
}
echo "<pre>";
// Run until timeout or all processing has finished
while(time() - $start < $timeout)
{
echo (time() - $start), " seconds\n";
clearstatcache(); // Required since PHP will cache for file_exists
$running = array();
foreach($items as $item)
{
// If the pid file still exists the process is still running
if (file_exists("$dir/proc.$id.$item.pid")) {
$running[] = $item;
}
}
if (empty($running)) break;
echo implode($running, ','), " running\n";
flush();
sleep(1);
}
// Clean up if we timeout out
if (!empty($running)) {
clearstatcache();
foreach ($items as $item) {
// Kill process of anything still running (i.e. that has a pid file)
if(file_exists("$dir/proc.$id.$item.pid")
&& $pid = file_get_contents("$dir/proc.$id.$item.pid")) {
posix_kill($pid, 9);
unlink("$dir/proc.$id.$item.pid");
// Would want to log this in the real world
echo "Failed to process: ", $item, " pid ", $pid, "\n";
}
// delete the useless data
unlink("$dir/proc.$id.$item.out");
}
} else {
echo "Successfully processed all items in ", time() - $start, " seconds.\n";
foreach ($items as $item) {
// Grab the processed data and delete the file
echo(file_get_contents("$dir/proc.$id.$item.out"));
unlink("$dir/proc.$id.$item.out");
}
}
echo "</pre>";
?>
Run Code Online (Sandbox Code Playgroud)
proc.php
<?php
$dir = realpath(dirname(__FILE__));
$id = $argv[1];
$item = $argv[2];
// Write out our pid file
file_put_contents("$dir/proc.$id.$item.pid", posix_getpid());
for($i=0;$i<80;++$i)
{
echo $item,':', $i, "\n";
usleep(250000);
}
// Remove our pid file to say we're done processing
unlink("proc.$id.$item.pid");
?>
Run Code Online (Sandbox Code Playgroud)
将test.php和proc.php放在服务器的同一文件夹中,加载test.php并享受.
你当然需要nohup(unix)和PHP cli来实现这一点.
很多乐趣,我可能会在以后找到它的用途.
使用像Beanstalkd这样的外部工作队列,你的PHP脚本也会编写一堆作业.您有尽可能多的工作进程从beanstalkd中提取作业并尽快处理它们.你可以像拥有内存/ CPU那样增加工作量.您的工作机构应该包含尽可能少的信息,可能只是您点击数据库的一些ID.beanstalkd有一大堆客户端API,本身有一个非常基本的API,想想memcached.
我们使用beanstalkd来处理我们所有的后台工作,我喜欢它.易于使用,速度非常快.