【问题标题】:How use multi-threading with this如何使用多线程
【发布时间】:2018-09-01 09:54:23
【问题描述】:

我一直在阅读有关 PHP 多线程的文章,但我很难将它集成到我的命令行 php 脚本中。

我读过multithreadingmultithread foreach

但我真的不确定。任何想法如何在这里应用多线程?我在这里需要多线程的原因是 Telnet 需要永远(参见 shell 脚本)。但我不能同时写入我的数据库($stmt2)。我正在使用 $stmt->fetch 遍历我的设备列表。

也许我应该执行run task specifically 之类的操作,只在任务中调用 telnet/shell 脚本,例如:

$task = new class extends Thread {
    private $response;

    public function run()
    {
        $content = file_get_contents("http://google.com");
        preg_match("~<title>(.+)</title>~", $content, $matches);
        $this->response = $matches[1];
    }
};

$task->start() && $task->join();

var_dump($task->response); // string(6) "Google"

但是,当我尝试将其添加到下面的代码中时出现错误:

PHP Parse error:  syntax error, unexpected T_CLASS in /opt/IBM/custom/NAC_Dslam/calix_swVerThreaded.php on line 100

这是行:

$task = 新类 ...

我的脚本如下所示:

$stmt =$mysqli->prepare("SELECT ip, model FROM TableD WHERE vendor = 'Calix' AND model in ('C7','E7') AND  sw_ver IS NULL LIMIT 6000"); //AND ping_reply IS NULL AND software_version IS NULL 
$stmt->bind_result($ip, $model); //list of ip's
if(!$stmt->execute())
{
    //err
}
$stmt2 = $mysqli2->prepare("UPDATE TableD SET sw_ver = ?
                            WHERE vendor = 'Calix'
                            AND ip = ? ");

$stmt2->bind_param("ss", $software, $ip);

while($stmt->fetch()) {
  //initializing var's
  if(pingAddress($ip)=="alive") { //Ones that don't ping are dead to us. 
    ///////this is the part that takes forever and should be multi-threaded/////
    //Call shell script to telnet to calix dslam and get version for that ip
    if($model == "C7"){

    $task = new class extends Thread {
        private $itsOutput;

        public function run()
        {
            exec ("./calix_C7_swVer.sh $ip", $itsOutput);//takes forever/telnet
                                                   //in shell script. Can't 
                                                   //be fixed. Each time I 
                                                   //call this script it's a 
                                                   //different ip
        }
    };
    $task->start() && $task->join();
    var_dump($task->itsOutput); //should be returned output above //takes forever to telnet
        //$output = $task->itsOutput;                                             
        $output2=array_reverse($output,true);
        if (!(preg_grep("/DENY/", $output2))){
          $found = preg_grep("/COMPLD/", $output2);
          $ind = key($found);
          $version = explode(",", $output[$ind+1]);
          if(strlen($version[3])>=1) { //if sw ver came back in an acceptable size
            $software = $version[3];
            $software = trim($software,'"'); //trim double quote (usually is there)
            print "sw ver after trim: " . $software . "\n"; 
            if(!$stmt2->execute()) { //write sw version to netcool db 
               $tempErr = "Failed to insert into dslam_elements_nac: " . $stmt2->error;
               printf($tempErr . "\n"); //show mysql execute error if exists  
               $err->logThis($tempErr);
            }
            if(!$stmtX->execute()) { //commit it
              $tempErr = "Failed to commit dslam_elements_nac: " . $stmtX->error;
              printf($tempErr . "\n");  //show mysql execute error if exists  
              $err->logThis($tempErr);
            }
          } //we got a version back
          else { //version not retrieved
              //error processing
          } //didn't get sw ver
        } //not deny
    } //c7
    else if($model == "E7") {
        exec ("./calix_E7_swVer.sh $ip", $output);
        $output2=array_reverse($output,true);
        if (!(preg_grep("/DENY/", $output2))){
          $found = preg_grep("/yes/", $output2);
          $ind = key($found);
          $version = explode("  ", $output[$ind]);
          if(strlen($version[5])>=1) { //if sw ver came back in an acceptable size
            $software = $version[5];
            print "sw ver after trim: " . $software . "\n"; 
            if(!$stmt2->execute()) { //write sw version to netcool db       
              $tempErr = "Failed to insert into dslam_elements_nac: " . $stmt2->error;
              printf($tempErr . "\n");  //show mysql execute error if exists  
              $err->logThis($tempErr);
            }
            if(!$stmtX->execute()) { //commit it
              //err processing
            }
          } //we got a version back
          else { //version not retrieved
             //handle it
          } //didn't get sw ver
      } //not deny
    } 
} //while

更新 我正在尝试这个(pcntl_fork),但它似乎不是我所需要的,因为当我睡眠(30)时,我认为这与我的 shell 脚本调用类似,其他进程不会继续并执行下一个一个。

<?php

declare(ticks = 1);

$max=10;
$child=0;
$res = array("aabc", "bcd", "cde", "eft", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "aabc", "bcd", "cde", "eft", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq");
function sig_handler($signo) {
  global $child;
  switch ($signo) {
   case SIGCHLD:
     //echo "SIGCHLD receivedn";
     // clean up zombies
     $pid = pcntl_waitpid(-1, $status, WNOHANG);
     $child -= 1;
    //exit;
  }
}

   pcntl_signal(SIGCHLD, "sig_handler");

   //$website_scraper = new scraper();

    foreach($res as  $r){
    while ($child >= $max) {
        sleep(5); //echo " - sleep $child n";
        //pcntl_waitpid(0,$status);
   }
   $child++;
    $pid=pcntl_fork();


    if ($pid==-1) {
        die("Could not fork:n");
    }
    elseif ($pid) {
        // we're in the parent fork, dont do anything
    } 
    else {
        //example of what a child process could do:
        print "child process stuff \n";
        sleep(30);
                //$website_scraper -> scraper("http://foo.com");
        exit;
    }
    while(pcntl_waitpid(0, $status) != -1) { //////???
        $status = pcntl_wexitstatus($status);
        echo "child $status completed \n";
    }
    print "did stuff \n";
}
?>

【问题讨论】:

  • 无论如何,新部分都被注释掉了。我的 php 版本是 5.3.3。新的来自我尝试使用的互联网示例,它似乎不允许我同时运行多个 shell 脚本。
  • @bishop - 我看到你的评论是关于我第一次尝试使用新线程。我目前正在尝试的是 pcntl_fork。
  • 明确一点,pcntl_fork 创建了一个新的进程,因此不是多线程
  • 如果 pcntl_fork 允许我同时运行我的 shell 脚本,并稍后一起处理结果,那没关系。这是有人推荐的,但我没有看到它同时运行,就像我上面所说的那样。有什么建议@bishop?

标签: php sql multithreading telnet


【解决方案1】:

我一直在阅读关于 PHP 多线程的文章

不要。 PHP 线程的实用性非常有限,因为它不能在 Web 服务器环境中使用。它只能在命令行脚本中使用。

PHP pthreads 扩展的作者has written

pthreads v3 仅限于在 CLI 中运行:我花了很多年时间试图解释 Web 服务器中的线程根本没有意义,在 1,111 次 pthreads 提交之后,我意识到,我的建议被忽视了。

因此,我向铁的事实提出建议:除了 CLI,您不能在任何地方安全且明智地使用 pthread。

如果您需要与多个网络设备并行通信,请考虑使用stream_select 执行异步 I/O,或运行多个 PHP 进程作为工作队列的一部分来管理连接。

【讨论】:

  • 你有一个例子说明我可以如何做你建议的事情吗?我正在尝试使用 Thread,但出现错误。请参阅上面我在哪里添加我尝试过的内容。
  • 你有我的例子吗?我查看了您提供的链接,但不确定它如何适用于我正在做的事情。
猜你喜欢
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多