PHPプログラムに関する各種メモ書き

amphp/amp を使って PHP7 で非同期(並列)処理

PHP8.1からは Fibers を使って非同期処理を記述することができますが
PHP 7でも amphp/amp を使う事でとても簡単に非同期処理を記述・実行することができます。

● 1. amphp/ampのインストール

composer require amphp/amp
composer require amphp/parallel-functions

● 2. 非同期処理の記述

例として3つのWEBサイトへ非同期でアクセスして、取得したhtmlのバイト数を返すプログラムを書いてみます

test.php

<?php

require_once './vendor/autoload.php';

use function Amp\ParallelFunctions\parallelMap;
use function Amp\Promise\wait;

function testFunc()
{
  $responses = wait(parallelMap([
      'https://stackoverflow.com/',
      'https://google.com/',
      'https://github.com/',
  ], function ($url) {
    $options = stream_context_create(array('ssl' => array(
      'verify_peer'      => false,
      'verify_peer_name' => false
    )));
    return file_get_contents($url, false, $options);
  }));

  echo strlen($responses[0]) . "\n";
  echo strlen($responses[1]) . "\n";
  echo strlen($responses[2]) . "\n";
}

function format_microtime ( $time, $format = null )
{
  if (is_string($format)) {
    $sec  = (int)$time;
    $msec = (int)(($time - $sec) * 100000);
    $formated = date($format, $sec). '.'. $msec;
  } else {
    $formated = sprintf('%0.5f', $time);
  }
  return $formated;
}



$start_time = microtime(true);

// 処理の実行
testFunc();

$end_time        = microtime(true);
$processing_time = $end_time - $start_time;
echo "処理時間:".format_microtime($processing_time)."秒\n";

● 3. 同じ処理を非同期を使わずに記述してみる

<?php

require_once './vendor/autoload.php';

function testFunc()
{
  $options = stream_context_create(array('ssl' => array(
    'verify_peer'      => false,
    'verify_peer_name' => false
  )));
   
  $responses[] = file_get_contents('https://stackoverflow.com/', false, $options);
  $responses[] = file_get_contents('https://google.com/', false, $options);
  $responses[] = file_get_contents('https://github.com/', false, $options);

  echo strlen($responses[0]) . "\n";
  echo strlen($responses[1]) . "\n";
  echo strlen($responses[2]) . "\n";
}

function format_microtime ( $time, $format = null )
{
  if (is_string($format)) {
    $sec  = (int)$time;
    $msec = (int)(($time - $sec) * 100000);
    $formated = date($format, $sec). '.'. $msec;
  } else {
    $formated = sprintf('%0.5f', $time);
  }
  return $formated;
}



$start_time = microtime(true);

// 処理の実行
testFunc();

$end_time        = microtime(true);
$processing_time = $end_time - $start_time;

echo "処理時間:".format_microtime($processing_time)."秒\n";

● 4. 実行して比較する

 php test.php 

結果例

180126
51223
279741
処理時間:1.07782秒

● 4. 比較する

それぞれ10回ずつ実行した結果はこちらになります

ampを使った非同期実行
処理時間:0.89127秒
処理時間:0.84902秒
処理時間:1.52270秒
処理時間:1.29796秒
処理時間:1.51700秒
処理時間:0.99289秒
処理時間:0.97136秒
処理時間:0.83685秒
処理時間:0.86408秒
処理時間:1.06043秒

平均は 1.08 sec
(0.89127+0.84902+1.52270+1.29796+1.51700+0.99289+0.97136+0.83685+0.86408+1.06043)/10





非同期を使わず実行
処理時間:1.62977秒
処理時間:1.55046秒
処理時間:1.56966秒
処理時間:1.76191秒
処理時間:1.55104秒
処理時間:1.69673秒
処理時間:1.74086秒
処理時間:1.57090秒
処理時間:1.69566秒
処理時間:1.65347秒

平均は : 1.64 sec (1.62977+1.55046+1.56966+1.76191+1.55104+1.69673+1.74086+1.57090+1.69566+1.65347)/10

● 注意点 WEBアプリで使用する場合は子プロセス生成に失敗します

(ウェブサーバーの設定権限によりけりだとは思いますが、WEBサーバから実行されたPHPの場合はうまく子プロセスが起動できずエラーとなります。)

No.2109
12/08 16:23

edit