php多线程问题

php多线程问题,php,multithreading,curl,semaphore,Php,Multithreading,Curl,Semaphore,我正在编写一个php cron作业,它使用curl读取数千个提要/网页,并将内容存储在数据库中。如何将线程数限制为6个?i、 例如,尽管我需要扫描数千个提要/网页,但我希望在任何时候只有6个curl线程处于活动状态,这样我的服务器和网络就不会陷入困境。我可以在Java中使用wait、notify、notify对象的所有方法轻松地完成这项工作。我应该构建自己的信号量还是php提供任何内置函数?首先,php没有线程,但它有进程控制: 我围绕这些函数构建了一个类,以帮助满足我的多进程需求 我也有类似

我正在编写一个php cron作业,它使用curl读取数千个提要/网页,并将内容存储在数据库中。如何将线程数限制为6个?i、 例如,尽管我需要扫描数千个提要/网页,但我希望在任何时候只有6个curl线程处于活动状态,这样我的服务器和网络就不会陷入困境。我可以在Java中使用wait、notify、notify对象的所有方法轻松地完成这项工作。我应该构建自己的信号量还是php提供任何内置函数?

首先,php没有线程,但它有进程控制:

我围绕这些函数构建了一个类,以帮助满足我的多进程需求

我也有类似的情况。我保存了从cron开始的进程及其状态的日志。我正在从一个相关的cron工作中检查它们

编辑(更多详细信息):

在我的项目中,我记录对数据库的所有关键更改。如果变更符合行动标准,则可采取行动。所以我现在做的和你不一样。然而,也有一些相似之处

当我派生一个新进程时,我在DB表中输入它的pid。然后,下次cron作业启动时,它所做的部分工作是检查进程是否正确完成,然后在该DB表中将操作标记为已完成

你没有给出很多关于你的项目的细节。所以我只想提出一个建议:

  • DB表包含要下载的资源的URL
  • 另一个表保存运行进程的PID
  • 每小时运行一次的cron作业将遍历表并下载资源并将其存储在数据库中。但是,它首先检查pid表中是否有完整/失效/正在运行的进程,并采取相应的行动。在这里,您可以将进程限制为6个
取决于项目的大小,这可能看起来有些过头了。然而,我已经考虑了很长一段时间,我想跟踪所有这些分叉过程。分叉可能是有风险的业务,并可能导致系统资源过载(从经验上讲;)

我也想听听其他的技巧。

我在

当我玩proc_open时,我的一些代码
我对proc_close(10到30秒)有问题,所以我只是使用linux命令kill终止了进程

Curl有时会在不同的服务器(ubuntu、centos)上为我冻结,但不是在所有服务器上,所以我会杀死任何超过40秒的“子”进程,因为通常脚本最多需要10秒,我宁愿重做,也不愿等待一分钟左右Curl解除冻结



$options=array();
$option['sleep-after-destroy']=0;
$option['sleep-after-create']=0;
$option['age-max']=40;
$option['dir-run']=dirname(__FILE__);
$option['step-sleep']=1;
$option['workers-max']=6;
$option['destroy-forcefull']=1;

$workers=array();

function endAWorker($i,$cansleep=true) {
        global $workers;
        global $option;
        global $child_time_limit;
        if(isset($workers[$i])) {
                @doE('Ending worker [['.$i.']]'."\n");
                if($option['destroy-forcefull']==1) {
                        $x=exec('ps x | grep "php check_working_child.php '.$i.' '.$child_time_limit.'" | grep -v "grep" | grep -v "sh -c"');
                        echo 'pscomm> '.$x."\n";
                        $x=explode(' ',trim(str_replace("\t",' ',$x)));
                        //print_r($x);
                        if(is_numeric($x[0])) {
                                $c='kill -9 '.$x[0];
                                echo 'killcommand> '.$c."\n";
                                $x=exec($c);
                        }
                }
                @proc_close($workers[$i]['link']);
                unset($workers[$i]);
        }
        if($cansleep==true) {
                sleep($option['sleep-after-destroy']);
        }
}

function startAWorker($i) {
        global $workers;
        global $option;
        global $child_time_limit;

        $runcommand='php check_working_child.php '.$i.' '.$child_time_limit.' > check_working_child_logs/'.$i.'.normal.log';
        doE('Starting [['.$i.']]: '.$runcommand."\n");
        $workers[$i]=array(
                'desc' => array(
                        0 => array("pipe", "r"),
                        1 => array("pipe", "w"),
                        2 => array("file", 'check_working_child_logs/'.$i.'.error.log', "a")
                        ),
                'pipes'                 => null,
                'link'                  => null,
                'start-time'    => mktime()
                );
        $workers[$i]['link']=proc_open(
                $runcommand,
                $workers[$i]['desc'],
                $workers[$i]['pipes'],
                $option['dir-run']
                );
        sleep($option['sleep-after-create']);
}

function checkAWorker($i) {
        global $workers;
        global $option;
        $temp=proc_get_status($workers[$i]['link']);
        if($temp['running']===false) {
                doE('Worker [['.$i.']] finished'."\n");
                if(is_file('check_working_child_logs/'.$i.'.normal.log') && filesize('check_working_child_logs/'.$i.'.normal.log')>0) {
                        doE('--------'."\n");
                        echo file_get_contents('check_working_child_logs/'.$i.'.normal.log');
                        doE('-------'."\n");
                }
                endAWorker($i);
        } else {
                if($option['age-max']>0) {
                        if($workers[$i]['start-time']+$option['age-max']$v) {
                endAWorker($i,false);
        }
        @doE('Done killing workers.'."\n");
}

register_shutdown_function('endAllWorkers');

while(1) {
        $step++;
        foreach($workers as $index=>$v) {
                checkAWorker($index);
        }
        if(count($workers)==$option['workers-max']) {
        } elseif(count($workers)$option['workers-max']) {
                $wl=array_keys($workers);
                $wl=array_pop($wl);
                doE('Killing worker [['.$wl.']]');
                endAWorker($wl[0]);
        }
}

并创建一个名为“check_working_child.php”的文件来完成所有工作,第一个参数是实例号,第二个参数是时间限制
php check\u working\u child.php 5 60
意味着你是第五个孩子,可以跑60秒


如果上面的代码没有运行,请告诉我,我将使用pastebin或其他工具发布它。

PHP没有线程化。除非您使用的是curl_multi*函数族,否则您的curl请求将一直阻止,直到完成为止。我最终使用库来满足我的需要。没有进程,没有线程。谢谢你的快速回答。如何在6个进程之间同步计数器?两个进程不应该试图同时更新计数器。我已经在答案中添加了一些细节。我不知道你的项目是如何组织的,所以我不能确定这是否适合你,但我希望它能帮助你。