>  기사  >  백엔드 개발  >  PHP 비동기 코루틴 개발: 대용량 파일 업로드 및 다운로드 문제 해결

PHP 비동기 코루틴 개발: 대용량 파일 업로드 및 다운로드 문제 해결

PHPz
PHPz원래의
2023-12-18 17:09:31959검색

PHP 비동기 코루틴 개발: 대용량 파일 업로드 및 다운로드 문제 해결

네트워크 기술의 발전과 애플리케이션 시나리오의 지속적인 확장으로 인해 대용량 파일 업로드 및 다운로드는 많은 웹 애플리케이션에서 직면한 문제가 되었습니다. 기존 처리 방법은 시간이 많이 걸리고 비효율적인 경우가 많지만, PHP 비동기 코루틴 개발은 이러한 문제를 효과적으로 해결할 수 있습니다.

최근 몇 년간 PHP 언어의 비동기 프로그래밍 기술이 점차 널리 사용되고 있으며, 그 중 코루틴 기술이 실제 개발에 더욱 널리 사용되고 있습니다. 코루틴은 스레드가 중단되고 일부 이벤트가 발생할 때까지 기다린 다음 스레드 실행을 재개할 수 있는 고급 형태의 사용자 스레딩입니다. 일반인의 관점에서 이는 코드 실행 중에 다른 작업을 수행하기 위해 CPU를 적극적으로 포기하는 것을 의미합니다.

대용량 파일 업로드 및 다운로드에 PHP 비동기 코루틴 개발을 적용하는 방법은 아래에서 자세히 소개하겠습니다.

1. 대용량 파일 업로드

웹 애플리케이션에서 대용량 파일 업로드는 일반적으로 HTTP 프로토콜을 통해 구현됩니다. 사용자가 대용량 파일을 업로드하면 서버는 파일을 메모리로 읽어 들여 디스크에 써야 합니다. 이 프로세스에는 많은 시간과 리소스가 필요합니다. 기존 처리 방법의 경우 대용량 파일이 업로드되면 서버는 업로드가 완료될 때까지 기다리며 동시에 다른 요청을 처리할 수 없습니다. 이는 리소스를 낭비할 뿐만 아니라 사용자 경험에도 영향을 미칩니다.

코루틴 기반 솔루션:

1. 클라이언트는 파일을 조각으로 서버에 업로드합니다. 이는 H5의 FormData API 및 XMLHttpRequest 객체를 사용하여 구현됩니다. 2. 서버는 업로드 요청을 받은 후 조각 수를 확인합니다. 업로드된 파일이 파일 크기와 일치합니까? 그렇다면 수신된 조각을 대상 파일에 저장하십시오.

3. 일치하지 않으면 오류 메시지가 반환됩니다. 파일 블록이 수신되지 않으면 업로드된 다른 블록을 정리하여 반제품 파일이 생성되지 않도록 해야 합니다.

4. 업로드가 완료된 후 서버에서 파일 속성 등을 조작할 수 있습니다. 파일이 상대적으로 큰 경우 CPU에 대한 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. 대용량 파일 다운로드

웹 애플리케이션에서는 대용량 파일 다운로드도 HTTP 프로토콜을 통해 구현됩니다. 사용자가 대용량 파일을 다운로드해야 하는 경우 서버는 디스크에서 파일을 읽어 클라이언트로 보내야 하며 이 과정에도 많은 시간과 리소스가 소요됩니다. 기존 처리 방법에서는 서버가 전체 파일을 한 번에 메모리로 읽어 클라이언트에 전송하는 경우 리소스가 낭비될 뿐만 아니라 서버가 충돌할 수도 있습니다.

코루틴 기반 솔루션:

첫 번째, 매번 디스크에서 특정 데이터 블록을 읽어 클라이언트로 보냅니다.

두 번째, 코루틴을 사용하여 제어하고, 특정 양의 데이터가 나올 때마다 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 비동기 코루틴을 자세히 소개합니다. 대용량 파일 업로드 및 다운로드를 위한 애플리케이션을 개발하고 구체적인 코드 구현 예제를 제공합니다. 실제 개발에서 코루틴 기반 비동기 프로그래밍 기술을 사용하면 웹 애플리케이션의 처리 성능과 사용자 경험을 효과적으로 향상시킬 수 있으며 이는 개발자가 심층적으로 연구하고 탐색할 가치가 있습니다.

위 내용은 PHP 비동기 코루틴 개발: 대용량 파일 업로드 및 다운로드 문제 해결의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.