php多进程-深入解析PHP伪多线程和多进程

2023-08-23 0 8,884 百度已收录

本文主要为大家详细介绍PHP伪多线程和多进程的深入分析。 具有一定的参考价值,可以借鉴。

感兴趣的朋友们,跟随512笔记小玲一起来看看吧!

(伪)多线程:使用外力

利用WEB服务器本身的多线程来处理,从WEB服务器中多次调用我们需要实现多线程的程序。

引用:

我们知道PHP本身不支持多线程,但是我们的WEB服务器支持多线程。

也就是说,可以多人同时一起参观。 这也是我在PHP中实现多线程的基础。

假设我们现在正在运行文件 a.php。 但我请求WEB服务器在程序中运行另一个b.php

那么这两个文件就会同时执行。

(PS:发送连接请求后,WEB服务器都会执行,不管客户端是否已经退出)

有时候,我们要运行的并不是另一个文件,而是这个文件中的一部分代码。 怎么做?

其实参数就是用来控制a.php运行哪个程序的。

让我们看一个例子:

代码如下所示:


打开result_a.log和result_b.log,比较两个文件的访问时间。 你会发现这两个确实运行在不同的线程中。 有些时候是完全一样的。

上面只是一个简单的例子,你可以改进成其他方式。

既然PHP也可以多线程了,那么问题就来了,那就是同步的问题。 我们知道PHP本身并不支持多线程。 所以Java中不会有synchronize这样的方式。 那我们该怎么办呢。

1、尽量不要访问同一个资源,防止冲突。 但同时你可以像数据库一样进行操作。 因为数据库支持并发操作。 所以在多线程PHP中

不要将数据写入同一文件。 如果一定要写,请使用其他方法来同步。 比如调用flock来锁定文件等。或者构建一个临时文件,在另一个线程中等待这个文件消失 while (file_exits('xxx')); 这意味着,当临时文件存在时,就意味着虽然该线程正在操作,但如果没有这个文件,就意味着其他线程已经释放了这个文件。

2、runThread执行fputs后尽量不要从socket读取数据。 要实现多线程,需要使用非阻塞模式。 也就是fgets之类的函数时立即返回。所以读写数据会出现问题。 如果使用阻塞模式,程序就不是多线程的。 它必须等待上一次的返回才能执行下一个程序。 所以如果需要交换数据,可以借助外部文件或者数据来完成。 如果你确实想要的话,可以使用socket_set_nonblock($fp)来实现。

说了这么多,这有什么实际意义吗? 我什么时候需要使用这些技术?

答案是肯定的。 谁都知道。 在不断读取网络资源的应用程序中,网络的速度是一个两难的选择。 如果使用更多这样的方法php多进程,可以使用多个线程同时读取不同的页面。

我做了一个程序,可以从8848、soaso等商场网站搜索信息。 另一个从阿里巴巴网站读取商业信息和公司名录的程序也使用了这项技术。 因为这两个程序不断地链接到它们的服务器来读取信息并将其保存到数据库中。 利用这种技术可以完全消除等待响应的困境。

多进程:使用PHP的进程控制函数(PCNTL/线程控制函数)

它只能在Unix Like操作系统中使用,Windows不可用。

编译php时需要添加--enable-pcntl,建议只在CLI模式下运行,不要在WEB服务器环境下运行。

php多进程-深入解析PHP伪多线程和多进程

以下是简单的测试代码:

代码如下所示:

declare(ticks=1);
$bWaitFlag = FALSE; /// 是否等待进程结束
$intNum = 10;           /// 进程总数
$pids = array();        ///  进程PID数组
echo ("Startn");
for($i = 0; $i < $intNum; $i++) {
  $pids[$i] = pcntl_fork();/// 产生子进程,而且从当前行之下开试运行代码,而且不继承父进程的数据信息
  if(!$pids[$i]) {
    // 子进程进程代码段_Start
    $str="";
    sleep(5+$i);
    for ($j=0;$j " . time() . " $str n";
    exit();
    // 子进程进程代码段_End
  }
}
if ($bWaitFlag)
{
  for($i = 0; $i  " . time() . "n";
  }
}
echo ("Endn");

运行结果如下:

代码:[复制到剪贴板][qiao@oicq qiao]$ phptest.php

开始

结尾

[qiao@oicq qiao]$ ps -aux | grep “php”

巧 32275 0.0 0.5 49668 6148pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32276 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32277 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32278 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32279 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32280 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32281 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32282 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32283 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32284 0.0 0.5 49668 6152pts/1 S 14:03 0:00 /usr/local/php4/b

巧 32286 0.0 0.0 1620 600pts/1 S 14:03 0:00 grep php

[qiao@oicq qiao]$ 0 -> 1133503401

1 -> 1133503402 *

2 -> 1133503403 **

3 -> 1133503404 ***

4 -> 1133503405 ****

5 -> 1133503406 *****

6 -> 1133503407*****

7 -> 1133503408 *****

8 -> 1133503409********

9 -> 1133503410 **********

[qiao@oicq qiao]$

如果$bWaitFlag=TURE,则结果如下:

代码:[复制到剪贴板][qiao@oicq qiao]$ phptest.php

开始

0 -> 1133503602

等待 0 -> 1133503602

1 -> 1133503603 *

等待 1 -> 1133503603

2 -> 1133503604**

等待2-> 1133503604

3 -> 1133503605 ***

等待3-> 1133503605

4 -> 1133503606 ****

等待4-> 1133503606

5 -> 1133503607 *****

等待5-> 1133503607

6 -> 1133503608*****

等待 6 -> 1133503608

7 -> 1133503609 *****

等待 7 -> 1133503609

8 -> 1133503610********

php多进程-深入解析PHP伪多线程和多进程

等待8-> 1133503610

9 -> 1133503611 **********

等待 9 -> 1133503611

结尾

[qiao@oicq qiao]$

从多进程计数器示例可以看出php多进程,使用pcntl_fork()后,会生成一个子进程,子进程运行的代码从pcntl_fork()之后的代码开始,并且子进程不继承父进程的数据信息(实际上是对父进程的数据进行了全新的复制),因此使用 if(!$pids[$i]) 来控制子进程实际运行的代码段。

暂时没有进行更详细的研究,可以参考我给出的指南的链接。

【第二条】尝试php命令行脚本多进程并发执行

除了fork之外,cli下还有另一种并发方式,看我的例子:

PHP不支持多线程,但是我们可以将问题转化为“多进程”来解决。 由于php中的pcntl_fork只能在unix平台上使用,因此本文尝试使用popen来代替。

这是一个例子:

并行调用的子程序代码:

代码如下所示:

<?php
/*   512笔记 www.512Pic.com   */
if($argc==1){
    echo("argvn");
}
$arg = $argv[1];
for($i=0; $i

主调用程序,调用子程序并同时收集子程序的输出

代码如下所示:

error_reporting(E_ALL);
$handle1 = popen('php sub.php php1', 'r');
$handle2 = popen('php sub.php php2', 'r');
$handle3 = popen('php sub.php php3', 'r');
echo "'$handle1'; " . gettype($handle1) . "n";
echo "'$handle2'; " . gettype($handle2) . "n";
echo "'$handle3'; " . gettype($handle3) . "n";
//sleep(20);
while(!feof($handle1) || !feof($handle2) || !feof($handle3) )
{
$read = fgets($handle1);
echo $read;
$read = fgets($handle2);
echo $read;
$read = fgets($handle3);
echo $read;
}
pclose($handle1);
pclose($handle2);
pclose($handle3);

这是我机器上的输出:

C:my_hunter>php exec.php

'资源 ID #4'; 资源

'资源 ID #5'; 资源

'资源 ID #6'; 资源

0.1.1147935331 执行 php1

0.1.1147935331 执行 php2

0.1.1147935331 执行 php3

php多进程-深入解析PHP伪多线程和多进程

1.1.1147935332 执行php1

0.2.1147935332 执行 php2

1.1.1147935332 执行php3

2.1.1147935333 执行php1

1.1.1147935333 执行php2

2.1.1147935333 执行php3

3.1.1147935334 执行php1

1.2.1147935334 执行php2

3.1.1147935334 执行php3

4.1.1147935335 执行php1

2.1.1147935335 执行php2

4.1.1147935335 执行php3

5.1.1147935336 执行php1

2.2.1147935336 执行php2

5.1.1147935336 执行php3

6.1.1147935337 执行php1

3.1.1147935337 执行php2

6.1.1147935337 执行php3

7.1.1147935338 执行php1

3.2.1147935338 执行php2

7.1.1147935338 执行php3

8.1.1147935339 执行php1

4.1.1147935339 执行php2

8.1.1147935339 执行php3

9.1.1147935340 执行php1

php多进程-深入解析PHP伪多线程和多进程

4.2.1147935340 执行php2

9.1.1147935340 执行php3

5.1.1147935341 执行php2

5.2.1147935342 执行php2

6.1.1147935343 执行php2

6.2.1147935344 执行php2

7.1.1147935345 执行php2

7.2.1147935346 执行php2

8.1.1147935347 执行php2

8.2.1147935348 执行php2

9.1.1147935349 执行php2

9.2.1147935350 执行php2

**总结:**

**主程序循环等待子进程,通过fgets或fread获取子进程的输出。 从时间戳来看,确实实现了并发执行。 **

-----------------------------------------------------------

未来的改进:

* popen打开的句柄是双向的。 如果需要与子进程交互,可以使用proc_open

* 使用链表和子函数来代替荒谬的写法 while(!feof($handle1)|| !feof($handle2) || !feof($handle3) )

* 使用fread一次性获取子进程已经形成的输出,而不是一次获取一行。

并发执行 shell 任务的调度程序。 该程序读取任务文件并同时执行上面的每一行命令。 可以设置同时存在的子进程数量:

代码如下所示:

/*
   主任务管理器
   并发的执行子任务列表
*/
include("../common/conf.php");
include("../common/function.php");
//开启的进程数
$exec_number = 40 ;
/***** main ********/
if($argc==1){
    echo("argvn");
}
$taskfile = $argv[1];
//tasklist
$tasklist = file($taskfile);
$tasklist_len = count($tasklist);
$tasklist_pos = 0;
$handle_list = array();
while(1)
{
    //子进程列表有空闲,则填充补齐子进程列表
    if($exec_number > count($handle_list) &&
            $tasklist_pos < $tasklist_len)
    {
        for($i=$tasklist_pos; $i $handle)
    {
        //$str = fgets($handle, 65536);
        $str = fread($handle, 65536);
        echo($str);
        if(feof($handle))
        {
            $end_handle_keys[] = $key;
            pclose($handle);
        }
    }
    //踢出停掉的子进程
    foreach($end_handle_keys as $key)
    {
        unset($handle_list[$key]);
        //var_dump($handle_list);
        //exit;
    }
}
tolog("nn*******************end**********************nn", "" ,  true);

附上一段Socket多进程接收的代码:

代码如下所示:

do {
 if (($msgsock = socket_accept($sock)) < 0) {
  echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "n";
  break;
 }
 $pid = pcntl_fork();
 if ($pid == -1) {
  die('could not fork');
 } else if (!$pid) {
  .....
  socket_write($msgsock, $msg, strlen($msg));
  do {
   ......
  } while (true);
   socket_close($msgsock);
 }
} while (true);

本文来自:

注:这里先介绍PHP伪多线程和多进程的深入分析。 更多相关文章,可以关注512笔记中的其他信息。

关键词:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php多进程-深入解析PHP伪多线程和多进程 https://www.wkzy.net/game/143488.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务