简单的PHP多线程实现

PHP中缺少“开箱即用”的多线程功能,因此发明了许多实现方式,包括扩展pthreadsAzaThread (CThread)甚至PHP开发人员自己的开发。

对我而言,主要缺点是这些解决方案太多了“麻烦”-并不总是需要在线程和父进程之间交换信息或节省资源。 始终应该具有快速,经济高效地解决问题的能力。

我想提前保留一个秘密,以防止在这篇文章中公开大秘密-对于初学者来说,这很可能是该语言的秘密,所以我决定发布它只是因为我自己遇到了问题,并且还没有找到现成的解决方案,所以我自己做了一种多线程仿真。

因此,任务是处理进入脚本的大量数据。 我的任务是处理文本信息的JSON数组,消化该脚本必须从中收集的信息,这对于PostgreSQL来说是同样大的提交。

首先,我们收集父文件中的数据:

index.php

// bigdata.json -    .      - ,     .. $big_json = file_get_contents('bigdata.json'); $items = json_decode($big_json, true); //   php    ,    , ,  unset($big_json); // ... 

数组大小在400mb左右波动(后来减少到〜50mb),并且所有信息都是文本信息。 不难估计所有内容的消化速度,并且考虑到脚本每15分钟在cron上运行一次,并且计算能力如此之高,因此性能受到很大影响。

接收到数据之后,您可以估计它们的数量,并在必要时计算每个CPU内核的必要线程数,或者可以简单地确定将有4个线程并计算每个线程的行数:

index.php

  // ... $threads = 4; $strs_per_thread = ceil(count($items) / $threads); //      -   echo "Items: ".count($items)."\n"; echo "Items per thread: ".$strs_per_thread."\n"; echo "Threads: ".$threads."\n"; // ... 

值得一提的是-这样的“正面”计算不会通过每个流的元素数量给出确切的结果。 需要更有可能简化计算。

现在最重要的是-我们为每个线程创建任务并运行它。 我们将执行此“前额”操作-为第二个文件-thread.php创建一个任务。 它将充当“流”,接收一系列元素以独立于主脚本进行处理和启动:

index.php

  // ... for($i = 0; $i < $threads; $i++){ if($i == 0) { passthru("(php -f thread.php 0 ".$strs_per_thread." & ) >> /dev/null 2>&1"); } if($i == $threads-1) { passthru("(php -f thread.php ".($strs_per_thread * $i)." ".count($items)." & ) >> /dev/null 2>&1"); } if(($i !== 0)&&($i !== $threads-1)) { $start = $strs_per_thread * $i + 1; $end = $start -1 + $strs_per_thread; passthru("(php -f thread.php ".$start." ".$end." & ) >> /dev/null 2>&1"); } } // ... 

passthru()函数用于运行控制台命令,但是脚本将等待每个命令完成。 为此,我们将启动命令包装在一组语句中,这些语句将启动进程并立即不返回任何内容,启动进程,父进程不会停止等待每个子进程执行:

 #  ,    ,   Linux- (php -f thread.php start stop & ) >> /dev/null 2>&1 

不幸的是,我不能肯定地说出这里到底发生了什么-我熟悉的Linuxoid向我建议了一组参数。 如果您能在评论中破译这种魔力,我将不胜感激,并将补充该帖子。

文件thread.php:

 $start = $argv[1]; $stop = $argv[2]; for ($i = $start; $i <= $stop; $i++) { // -          } 

通过这种非常简单的方法,您可以在PHP中实现多线程仿真。

如果我们将整个示例简化为干燥输出,那么我认为这听起来像是:命令行中的父线程启动子进程,告诉子进程要处理哪些信息。

当我说“仿真”时,我的意思是说,使用这种实现方法无法在线程之间或父子线程之间交换信息。 如果事先知道不需要这种特征是合适的。

Source: https://habr.com/ru/post/zh-CN448464/


All Articles