插件窝 干货文章 Guzzle下载100M大文件:如何避免阻塞主进程?

Guzzle下载100M大文件:如何避免阻塞主进程?

异步 使用 请求 文件 38    来源:    2025-03-16

在使用 Guzzle 下载大文件时,为了避免阻塞主进程,可以采用异步请求的方式。Guzzle 提供了异步请求的功能,允许你在下载文件的同时继续执行其他任务。以下是一个使用 Guzzle 异步下载大文件的示例:

1. 使用 Guzzle 的异步请求功能

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client();

// 发起异步请求
$promise = $client->getAsync('http://example.com/large-file.zip', [
    'sink' => '/path/to/save/large-file.zip' // 指定文件保存路径
]);

// 继续执行其他任务
echo "Downloading file in the background...\n";

// 等待异步请求完成
$promise->then(
    function ($response) {
        echo "File downloaded successfully!\n";
    },
    function ($exception) {
        echo "Download failed: " . $exception->getMessage() . "\n";
    }
);

// 保持主进程运行,直到异步请求完成
$promise->wait();

2. 使用 sink 选项

在 Guzzle 中,sink 选项允许你将响应内容直接写入文件,而不是将整个文件内容加载到内存中。这对于下载大文件非常有用,因为它可以避免内存耗尽的问题。

3. 使用 Promise 处理多个异步请求

如果你需要同时下载多个大文件,可以使用 Promise 来管理多个异步请求:

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client();

$promises = [
    'file1' => $client->getAsync('http://example.com/large-file1.zip', ['sink' => '/path/to/save/file1.zip']),
    'file2' => $client->getAsync('http://example.com/large-file2.zip', ['sink' => '/path/to/save/file2.zip']),
];

// 等待所有请求完成
$results = Promise\Utils::settle($promises)->wait();

foreach ($results as $key => $result) {
    if ($result['state'] === 'fulfilled') {
        echo "$key downloaded successfully!\n";
    } else {
        echo "$key download failed: " . $result['reason']->getMessage() . "\n";
    }
}

4. 使用 curl_multi_exec 进行更底层的控制

如果你需要更底层的控制,可以使用 PHP 的 curl_multi_exec 函数来实现异步下载。Guzzle 内部也是基于 cURL 的,但如果你需要更精细的控制,可以直接使用 cURL。

5. 使用队列或任务调度器

如果你在 Web 应用中下载大文件,可以考虑将下载任务放入队列中,使用任务调度器(如 Laravel 的队列系统)在后台处理下载任务,从而避免阻塞主进程。

总结

通过使用 Guzzle 的异步请求功能,你可以避免在下载大文件时阻塞主进程。结合 sink 选项,你可以有效地管理内存使用,确保下载过程不会导致内存耗尽。对于更复杂的场景,可以使用 Promise 来管理多个异步请求,或者使用队列系统来处理后台任务。