«

PHP 批量异步请求的方法

刚子 发布于 阅读:119


极简最优:单进程 + Swoole\Coroutine\Http\Client(协程批量)

<?php
// 需安装 Swoole 扩展(pecl install swoole)
Co\run(function () {
    $urls = [];                       // 你的 1000 条 URL
    for ($i = 0; $i < 1000; $i++) {
        $urls[] = "https://www.xx.com/test.php?order_no=$i";
    }

    foreach ($urls as $url) {
        go(function () use ($url) {
            $cli = new Swoole\Coroutine\Http\Client(parse_url($url, PHP_URL_HOST), 443, true);
            $cli->set([
                'timeout' => 0.05,   // 50 ms 超时,发完即走
                'ssl_verify_peer' => false,
            ]);
            $cli->get(parse_url($url, PHP_URL_PATH) . '?' . parse_url($url, PHP_URL_QUERY));
            $cli->close();           // 立即关闭,不等待响应
        });
    }
});
echo "1000 条已发出\n";

使用CURL

<?php
// fire.php
$urls   = [];
$total  = 20000;                     // 总请求数
$concur = 50;                       // 并发数,建议10~50(根据服务器配置调整)
$delay  = 50000;                    // 批次间隔(微秒),50ms

// 生成URL列表
for ($i = 0; $i < $total; $i++) {
    $urls[] = 'https://www.ss.com/test.php?order_no=' . $i;
}

// 过滤无效URL(避免无效请求消耗资源)
$urls = array_filter($urls, function($url) {
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
});

if (empty($urls)) {
    die("无有效URL可请求\n");
}

$chunks = array_chunk($urls, $concur);
$batchCount = count($chunks);
$currentBatch = 1;

foreach ($chunks as $batch) {
    // 1. 转义所有URL(防止命令注入,处理特殊字符)
    $escapedUrls = array_map('escapeshellarg', $batch);

    // 2. 构建单条curl命令,用--parallel并行处理当前批次(减少进程创建开销)
    $urlsStr = implode(' ', $escapedUrls);
    $cmd = "curl -s -m 1 -k --parallel --parallel-max {$concur} {$urlsStr} > /dev/null 2>&1 &";

    // 3. 执行命令(单批次仅1次系统调用)
    shell_exec($cmd);

    // 4. 输出进度(可选,便于监控)
    echo "已发送第{$currentBatch}/{$batchCount}批(共".count($batch)."条)\n";
    $currentBatch++;

    // 5. 批次间隔(最后一批无需等待)
    if ($currentBatch <= $batchCount) {
        usleep($delay);
    }
}

echo "共".count($urls)."条有效URL已分批异步发出\n";
?>

第三种方法

<?php
$total  = 20000;
$concur = 50;          // 同时并发的句柄数(可调 20~100)

$mh = curl_multi_init();
$chs = [];

// 1. 生成干净 URL
for ($i = 0; $i < $total; $i++) {
    $url = "https://www.x.cn/test.php?order_no=$i";
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => false, // 不取内容
        CURLOPT_TIMEOUT        => 1,     // 1 秒超时
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_NOSIGNAL       => true,  // 防止超时信号
    ]);
    curl_multi_add_handle($mh, $ch);
    $chs[] = $ch;

    // 每 $concur 条批量执行一次
    if (count($chs) >= $concur) {
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh, 0.001); // 非阻塞事件循环
        } while ($running);

        // 清理这批句柄
        foreach ($chs as $ch) {
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
        }
        $chs = [];
    }
}

// 2. 处理剩余不足 $concur 条
if ($chs) {
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh, 0.001);
    } while ($running);
    foreach ($chs as $ch) {
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
}

curl_multi_close($mh);
echo "done\n";