0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GoとPHPでの並行処理の違い

Last updated at Posted at 2025-01-18

はじめに

並行処理に特化しているとされるGoとウェブアプリの開発によく使われるPHPで並行処理の実現方法がどう違うのかまとめる。

GoとPHPの並行処理における比較

比較項目 Go PHP
基本設計 並行処理が言語レベルで組み込まれている 並行処理は追加の拡張やライブラリを使う必要がある。
プロセス 各リクエストは同じプロセスで処理される 各リクエストは違うプロセスで処理される。
軽量性 ゴルーチンは軽量で数千~数百万の並行タスクを処理可能。 マルチプロセスはリソースを多く消費し、スレッドベースは限定的。
実装の簡潔さ シンプルな構文で並行処理を記述可能 マルチプロセスやイベントループベースで複雑なコードになる場合が多い。
スケジューリング Goランタイムが自動でゴルーチンをスケジュール プロセスやスレッドのスケジューリングはOS任せ。
主な用途 並行処理が頻繁に必要で、高い性能を求めるアプリケーション(例:リアルタイム通信、マイクロサービス) ウェブアプリケーションの開発。並行処理は補助的な役割で、イベントループライブラリを利用して解決可能。

Goの並行処理の例

Goでは軽量スレッド(ゴルーチン)を使うため、簡潔なコードで高性能な並行処理が可能。

package main

import (
	"fmt"
	"time"
)

func task(name string) {
	for i := 1; i <= 5; i++ {
		fmt.Println(name, i)
		time.Sleep(500 * time.Millisecond)
	}
}

func main() {
	go task("Task A")
	go task("Task B")
	task("Main Task")
}

Goで平行処理を実現する際の注意点

複数のgoroutineから同じメモリ(変数)へ同時にアクセスする(そのうち1つは書き込みである)ことで、予期しないエラーの原因になる。この状態のことをRace Conditionという。

以下コードはnet/httpを使用したHTTPサーバで各リクエストがメモリ空間を共有することを確認する例。
リクエストハンドラ内の変数cは全てのリクエストにおいて同じメモリ上のデータを指す。 したがって、アクセスのたびに変数cがインクリメントされる。

複数のリクエストが同時に発生した場合、変数cへ同時アクセスが発生し、Race Conditionになり、予期しないエラーが発生する可能性がある。

package main

import (
	"fmt"
	"log"
	"net/http"
)

var c int

func main() {
	http.HandleFunc("/count", func(w http.ResponseWriter, r *http.Request) {
		// リクエスト毎に別のgoroutineで実行される
		// 複数のリクエストによって同時に書き込みが発生する可能があり、cが意図しない状態の場合がある
		c++
		fmt.Fprintf(w, "count: %d, address: %v", c, &c)
	})

	log.Fatal(http.ListenAndServe(":8080", nil))
}

PHPの並行処理の例

PHPは主に同期的な動作を想定して設計されていて、並行処理を実現するためには追加の拡張や工夫が必要。

マルチプロセス

pcntl_fork() を使用してプロセスをフォーク。
PHPはプロセスベースの動作が一般的で、スレッドを直接扱うことは少ない。

<?php
function task($name) {
    for ($i = 1; $i <= 5; $i++) {
        echo "$name $i\n";
        sleep(1);
    }
}

$pid = pcntl_fork();

if ($pid == -1) {
    die("Fork failed");
} elseif ($pid == 0) {
    // 子プロセス
    task("Child Process");
} else {
    // 親プロセス
    task("Parent Process");
    pcntl_wait($status); // 子プロセスの終了を待機
}

非同期ライブラリ

・非同期I/O操作(例: HTTPリクエスト、ファイル操作)に適している。
・プロセスやスレッドを生成せずに、シングルスレッド内で複数のタスクを処理。
・パフォーマンスが高く、Webサーバーのバックエンドで利用されることが多い。

<?php
require 'vendor/autoload.php';

$loop = React\EventLoop\Factory::create();

$loop->addTimer(1, function () {
    echo "Task 1 complete\n";
});

$loop->addTimer(2, function () {
    echo "Task 2 complete\n";
});

$loop->run();
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?