ホームページ  >  記事  >  バックエンド開発  >  PHP 非同期コルーチン開発: 大きなファイルのアップロードとダウンロードの問題を解決する

PHP 非同期コルーチン開発: 大きなファイルのアップロードとダウンロードの問題を解決する

PHPz
PHPzオリジナル
2023-12-18 17:09:31953ブラウズ

PHP 非同期コルーチン開発: 大きなファイルのアップロードとダウンロードの問題を解決する

ネットワーク テクノロジーの発展とアプリケーション シナリオの継続的な拡大に伴い、大きなファイルのアップロードとダウンロードが多くの Web アプリケーションで直面する問題になっています。従来の処理方法は多くの場合時間がかかり、非効率的ですが、PHP 非同期コルーチン開発はこれらの問題を効果的に解決できます。

近年、PHP言語の非同期プログラミング技術が徐々に普及してきており、その中でも実際の開発ではコルーチン技術が広く使われています。コルーチンはユーザー スレッドの高度な形式であり、スレッドを中断し、何らかのイベントが発生するのを待ってからスレッドの実行を再開できるようにします。平たく言えば、コードの実行中に他の操作を実行するために CPU を積極的に放棄することを意味します。

以下では、大きなファイルのアップロードとダウンロードにおける PHP 非同期コルーチン開発の応用について詳しく紹介します。

1. 大きなファイルのアップロード

Web アプリケーションでは、通常、大きなファイルのアップロードは HTTP プロトコルを通じて実装されます。ユーザーが大きなファイルをアップロードすると、サーバーはファイルをメモリに読み取ってディスクに書き込む必要があり、このプロセスには多くの時間とリソースがかかります。従来の処理方法では、大きなファイルがアップロードされると、サーバーはアップロードが完了するまで待機し、同時に他のリクエストを処理できなくなります。これはリソースを無駄にするだけでなく、ユーザー エクスペリエンスにも影響します。

コルーチンに基づくソリューション:

1. クライアントはファイルをスライス単位でサーバーにアップロードします。ここでは、H5 の FormData API と XMLHttpRequest オブジェクトを使用して実装します

#2 . サーバー アップロードリクエストを受信後、アップロードしたファイルのスライス数とファイルサイズが一致しているか確認し、一致していれば受信したスライスを対象ファイルに格納します。

3. 矛盾している場合は、エラー メッセージが返されます。ファイル ブロックの受信に失敗した場合は、中途半端なファイルが生成されるのを避けるために、アップロードされた他のブロックをクリーンアップする必要があります。

4. アップロード完了後、サーバー側でファイル属性等の操作が可能になります。ファイルが比較的大きい場合は、ファイルを非同期的に処理して、IO や CPU への集中的な影響を避けることができます。

以下はサンプル コードです:

<?php
// 启用协程运行时
SwooleRuntime::enableCoroutine();

$http = new SwooleHttpServer("127.0.0.1", 9501);

// 监听HTTP请求
$http->on("request", function ($request, $response) {

    // 从请求中获取分块数据
    $chunk = $request->rawContent();

    // 获取分块所属的文件名和分块编号
    $fileName = $_POST['fileName'];
    $chunkIndex = $_POST['chunkIndex'];

    // 将分块数据追加写入到目标文件中
    $fp = fopen($fileName, 'ab');
    fwrite($fp, $chunk);
    fclose($fp);

    // 判断是否上传完成
    if (intval($_POST['totalChunks']) == $chunkIndex + 1) {
        $response->end("Upload completed.");
    } else {
        $response->end("Upload success.");
    }
});

$http->start();

2. 大きなファイルのダウンロード

Web アプリケーションでは、大きなファイルのダウンロードも HTTP プロトコルを通じて実装されます。ユーザーが大きなファイルをダウンロードする必要がある場合、サーバーはディスクからファイルを読み取ってクライアントに送信する必要があり、このプロセスにも多くの時間とリソースがかかります。従来の処理方法では、サーバーがファイル全体を一度にメモリに読み込んでクライアントに送信すると、リソースが無駄になるだけでなく、サーバーがクラッシュする可能性があります。

コルーチンに基づくソリューション:

1. 毎回ディスクから特定のデータ ブロックを読み取り、クライアントに送信します

2. 制御、収量にコルーチンを使用します一定量のデータを送信した後に CPU を解放します 3. クライアントは現在のブロックを消費した後、サーバーにメッセージを送信し、次のデータ ブロックを入力します。コード:

<?php
// 启用协程运行时
SwooleRuntime::enableCoroutine();

$server = new SwooleHttpServer('127.0.0.1', 9502);

$server->on('request', function($request, $response) {
    $filePath = '/path/to/large/file';
    $startPos = 0;
    $readChunkSize = 8192;

    $fileSize = filesize($filePath);

    $response->header('Content-Type', 'application/octet-stream');
    $response->header('Accept-Ranges', 'bytes');

    // 读取和发送一块数据
    function readAndSendChunk($fp, $response, $startPos, $readChunkSize, $fileSize) {
        fseek($fp, $startPos);
        $maxLength = $fileSize - $startPos;
        if ($maxLength > $readChunkSize) {
            $maxLength = $readChunkSize;
        }
        $data = fread($fp, $maxLength);
        $response->write($data);
        return $startPos + $maxLength;
    }

    // 每发送一定量的数据后yield,让出CPU
    function sendByYield($fp, $response, $startPos, $readChunkSize, $fileSize) {
        while ($startPos < $fileSize) {
            $startPos = readAndSendChunk($fp, $response, $startPos, $readChunkSize, $fileSize);
            yield;
        }
        fclose($fp);
        $response->end();
    }

    // 检查是否支持断点续传
    $range = $request->header['range'];
    if ($range) {
        $status = '206 Partial Content';
        $range = explode('-', substr($range, 6));
        if ($range[0] === '') {
            $startPos = $fileSize - intval($range[1]);
        } else if ($range[1] === '') {
            $startPos = intval($range[0]);
        } else {
            $startPos = intval($range[0]);
            $readChunkSize = intval($range[1]) - $startPos + 1;
            $response->header('Content-Length', $readChunkSize);
        }
    } else {
        $status = '200 OK';
        $response->header('Content-Length', $fileSize);
    }

    $response->header('HTTP/1.1', $status);
    $response->header('Content-Disposition', 'attachment;filename="'.basename($filePath).'"');
    $response->header('Content-Range', 'bytes '.$startPos.'-'.($startPos+$readChunkSize-1).'/'.$fileSize);

    $fp = fopen($filePath, 'rb');
    fseek($fp, $startPos);

    $response->status(200);

    // 使用协程进行控制
    for ($i = 1; $i <= 5; $i++) {
        go(function() use ($fp, $response, $startPos, $readChunkSize, $fileSize) {
            yield from sendByYield($fp, $response, $startPos, $readChunkSize, $fileSize);
        });
    }
});

$server->start();

結論:

この記事では、大きなファイルのアップロードとダウンロードにおける PHP 非同期コルーチン開発のアプリケーションを詳細に紹介し、具体的なコードの実装例を示します。実際の開発では、コルーチン ベースの非同期プログラミング テクノロジを使用すると、Web アプリケーションの処理パフォーマンスとユーザー エクスペリエンスを効果的に向上させることができます。これは、開発者による詳細な調査と検討に値します。

以上がPHP 非同期コルーチン開発: 大きなファイルのアップロードとダウンロードの問題を解決するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。