Maison >développement back-end >tutoriel php >Développement de coroutines asynchrones PHP : résoudre le problème du téléchargement et du téléchargement de fichiers volumineux

Développement de coroutines asynchrones PHP : résoudre le problème du téléchargement et du téléchargement de fichiers volumineux

PHPz
PHPzoriginal
2023-12-18 17:09:31978parcourir

Développement de coroutines asynchrones PHP : résoudre le problème du téléchargement et du téléchargement de fichiers volumineux

Avec le développement de la technologie réseau et l'expansion continue des scénarios d'application, le téléchargement de fichiers volumineux est devenu un problème auquel sont confrontées de nombreuses applications Web. Les méthodes de traitement traditionnelles sont souvent longues et inefficaces, tandis que le développement de coroutines asynchrones PHP peut résoudre efficacement ces problèmes.

Ces dernières années, la technologie de programmation asynchrone du langage PHP a été progressivement largement utilisée, parmi lesquelles la technologie coroutine a été plus largement utilisée dans le développement réel. Une coroutine est une forme avancée de thread utilisateur qui permet à un thread de s'interrompre, d'attendre qu'un événement se produise, puis de reprendre l'exécution du thread. En termes simples, cela signifie abandonner activement le processeur pour effectuer d'autres opérations pendant l'exécution du code.

L'application du développement de coroutines asynchrones PHP dans le téléchargement et le téléchargement de fichiers volumineux sera présentée en détail ci-dessous.

1. Téléchargement de fichiers volumineux

Dans les applications Web, les téléchargements de fichiers volumineux sont généralement mis en œuvre via le protocole HTTP. Lorsqu'un utilisateur télécharge un fichier volumineux, le serveur doit lire le fichier en mémoire et l'écrire sur le disque. Ce processus prend beaucoup de temps et de ressources. Dans la méthode de traitement traditionnelle, une fois qu'un fichier volumineux est téléchargé, le serveur attendra la fin du téléchargement et ne pourra pas traiter d'autres demandes en même temps. Cela gaspille non seulement des ressources, mais affecte également l'expérience utilisateur.

Solution basée sur Coroutine :

1. Le client télécharge le fichier sur le serveur par tranches. Ceci est implémenté à l'aide de l'API FormData de H5 et de l'objet XMLHttpRequest. 2. Une fois que le serveur a reçu la demande de téléchargement, il vérifie le nombre de tranches de. le fichier téléchargé. Est-il cohérent avec la taille du fichier ? Si oui, stockez les tranches reçues dans le fichier cible.

3. S'ils sont incohérents, un message d'erreur sera renvoyé. Si un bloc de fichier ne parvient pas à être reçu, les autres blocs téléchargés doivent être nettoyés pour éviter de produire des fichiers semi-finis.

4. Une fois le téléchargement terminé, le serveur peut exploiter les attributs du fichier, etc. Si le fichier est relativement volumineux, le fichier peut être traité de manière asynchrone pour éviter une sensibilité gourmande en E/S et en CPU au CPU.

Ce qui suit est un exemple de code :

<?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. Téléchargement de fichiers volumineux

Dans les applications Web, les téléchargements de fichiers volumineux sont également implémentés via le protocole HTTP. Lorsqu'un utilisateur doit télécharger un fichier volumineux, le serveur doit lire le fichier à partir du disque et l'envoyer au client. Ce processus prend également beaucoup de temps et de ressources. Si, dans la méthode de traitement traditionnelle, le serveur lit l'intégralité du fichier en mémoire en une seule fois et l'envoie au client, cela gaspille non seulement des ressources, mais peut également provoquer un crash du serveur.

Solution basée sur la coroutine :

Premièrement, lisez un certain bloc de données du disque à chaque fois et envoyez-le au client

Deuxièmement, utilisez la coroutine pour le contrôle et cédez pour abandonner le processeur après chaque certaine quantité de données est envoyé

3. Une fois que le client a consommé le bloc actuel, il envoie un message au serveur et saisit la transmission de données du bloc suivant

Ce qui suit est un exemple de code :

<?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();

Conclusion :

Cet article. présente en détail les coroutines asynchrones PHP. Développez des applications pour le téléchargement et le téléchargement de fichiers volumineux et fournissez des exemples d'implémentation de code spécifiques. Dans le développement réel, l'utilisation de la technologie de programmation asynchrone basée sur la coroutine peut améliorer efficacement les performances de traitement et l'expérience utilisateur des applications Web, ce qui mérite une recherche et une exploration approfondies par les développeurs.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn