【问题标题】:Running PHP & Mysqli queries in Parallel并行运行 PHP 和 Mysqli 查询
【发布时间】:2016-10-17 01:18:25
【问题描述】:

我想从数千个预制的 sql 文件中提取数据。我有一个脚本可以在 PHP 中使用 Mysqli 驱动程序来完成我需要的工作,但它真的很慢,因为它一次只有一个 sql 文件。我修改了脚本以创建唯一的临时数据库名称,每个 sql 文件都加载到该名称中。数据被提取到存档数据库表中,然后临时数据库被转储。为了加快速度,我创建了一个由 4 个脚本组成的脚本,类似于下面的脚本,每个 for 循环都存储在它自己独特的 PHP 文件中(下面的代码仅用于快速演示正在发生的事情在 4 个单独的文件中),它们被设置为仅从源文件夹中获取 1/4 的文件。所有这些都完美运行,脚本运行,对文件处理的干扰为零。问题是我的性能提升似乎几乎为零。也许快了 10 秒 :( 我快速刷新了我的 PHPmyadmin 数据库列表页面,可以看到随时加载的 4 个不同的数据库,但我也注意到它看起来仍然或多或少地按顺序运行,因为数据库名称正在动态更改。我做了额外的步骤,为每个脚本创建一个唯一的用户,每个脚本都有自己的连接。没有改进。我可以让它与 mysqli / PHP 一起使用,还是我需要研究一些其他选项?我更喜欢这样做如果可以的话,全部使用 PHP(7.0 版)。我通过在浏览器中运行 PHP 脚本进行了测试。这是问题所在吗?我还没有编写任何代码来在命令行上执行它们并将它们设置为后台。一个最后一点,我的 mysql 数据库中的所有用户对连接等都没有限制。

$numbers = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20');


$numCount = count($numbers);
$a = '0';
$b = '1';
$c = '2';
$d = '3';

$rebuild = array();

echo"<br>";

for($a; $a <= $numCount; $a+=4){

if(array_key_exists($a, $numbers)){
    echo $numbers[$a]."<br>";
}

}

echo "<br>";

for($b; $b <= $numCount; $b+=4){

if(array_key_exists($b, $numbers)){
    echo $numbers[$b]."<br>";
}
}

echo "<br>";

for($c; $c <= $numCount; $c+=4){

if(array_key_exists($c, $numbers)){
    echo $numbers[$c]."<br>";
}

}

echo "<br>";

for($d; $d <= $numCount; $d+=4){

if(array_key_exists($d, $numbers)){
    echo $numbers[$d]."<br>";
}

}

【问题讨论】:

  • 嗯...您的代码一个接一个地运行,它们不会并行运行。换句话说,第二个for 循环在之前的所有内容完成之前不会运行。对于线程,您需要继承 Thread 类。阅读:mullie.eu/parallel-processing-multi-tasking-php
  • 我的错...每个 for 循环都是它自己的文件...我只是将其格式化以快速显示想法。
  • 哦,好的,我明白了。但无论如何,对于并行处理,您应该(“必须”)使用多个线程
  • 好的,那么我是否走在正确的道路上?我有四个文件不会与其他文件处理等混淆...?
  • 这是一种方式,但是在生产状态下,这将是非常浪费的。为 4 个并行任务(父 + 4 个子)使用 5 个连接不是这样做的方法,而是使用一个“父”进程来运行多个“子”进程而不会消耗更多的网络调用。这是线程的任务。有些人使用curl()fopen() 来加载这些子脚本......即使这样可行,正确且被接受的方法是使用Thread 子类。

标签: php mysql database mysqli


【解决方案1】:

试试这个:

<?php
    class BackgroundTask extends Thread {
        public $output;
        protected $input;

        public function run() {
            /* Processing here, use $output for... well... outputting data */

            // Here you would implement your for() loops, for example, using $this->input as their data

            // Some dumb value to demonstrate
            $output = "SOME DATA!";
        }

        function __construct($input_data) {
            $this->input = $input_data;
        }
    }

    // Create instances with different input data
    // Each "quarter" will be a quarter of your data, as you're trying to do right now
    $job1 = new BackgroundTask($first_quarter);
    $job1->start();

    $job2 = new BackgroundTask($second_quarter);
    $job2->start();

    $job3 = new BackgroundTask($third_quarter);
    $job3->start();

    $job4 = new BackgroundTask($fourth_quarter);
    $job4->start();

    // ==================

    // "join" the first job, i.e. "wait until it's finished"
    $job1->join();
    echo "First output: " . $job1->output;

    $job2->join();
    echo "Second output: " . $job2->output;

    $job3->join();
    echo "Third output: " . $job3->output;

    $job4->join();
    echo "Fourth output: " . $job4->output;
?>

通过 HTTP 对您自己的脚本进行四次调用时,您会无缘无故地超载连接。相反,您正在为可能试图访问您网站的其他用户占用空间。

【讨论】:

  • 感谢代码!正在扩展的线程类在哪里?
  • 看第一行,extends Thread。这包括使用线程的所有代码。
  • 我只是在 PHP 手册中看到了这个,没有意识到它是内置在 pthreads 扩展中的。好的,我的原始概念也可以,有 4 个不同的脚本,还是我可以只使用循环遍历所有文件并复制几次的原始概念?我最初的设计是为了防止文件处理问题,因为它在完成时也会删除 sql 文件。
  • 好吧,您可以使用四种不同的脚本(例如,在run() 方法中使用include()),一切都应该很好。但请记住,每个进程都并行运行,因此您应该检查每个进程的输出数据。
  • 好的,所以我可以使用所有四个,我想这是我有点困惑的地方。假设我将原始主脚本(一次只执行一个文件)放入 run() 方法中。这仍然会提高性能吗?在我看来,我想它会像往常一样运行,不会做任何特别的事情……对吗?
猜你喜欢
  • 2019-02-07
  • 2013-08-05
  • 1970-01-01
  • 2013-09-19
  • 1970-01-01
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
  • 2012-09-12
相关资源
最近更新 更多