You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel/PHP如何并行运行3个API数据获取函数?含调度器场景

并行运行API抓取任务的几种实用方案

嘿,这个需求在Laravel环境下完全可以实现,而且有几种不同的路子适配不同场景,我给你详细说说:

方案一:Laravel队列(首推!适配调度器场景)

既然你要用Laravel的调度器,那队列绝对是最贴合生态的选择——不仅能实现并行执行,还自带失败重试、任务监控这些贴心功能,长期维护起来超省心。

步骤很简单:

  1. 给每个API写队列任务
    给每个API的fetch方法单独创建一个队列任务类,比如:

    // app/Jobs/FetchApi1Data.php
    namespace App\Jobs;
    
    use App\Classes\api1;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Queue\SerializesModels;
    
    class FetchApi1Data implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        public function handle()
        {
            // 直接调用你的API类fetch方法
            (new api1())->fetch();
        }
    }
    

    照着这个模板,再创建FetchApi2Data和FetchApi3Data两个任务类就行。

  2. 调度器里分发任务
    打开app/Console/Kernel.php,在schedule方法里把三个任务一起分发——队列worker会自动并行处理它们:

    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            FetchApi1Data::dispatch();
            FetchApi2Data::dispatch();
            FetchApi3Data::dispatch();
        })->everyMinute();
    }
    

    划重点:别忘了先配置好队列驱动(比如Redis或者Database),然后启动队列worker:php artisan queue:work,不然任务只会存在队列里不会执行哦!

方案二:Guzzle并发请求(如果你的API是HTTP接口)

如果你的fetch方法本质就是发送HTTP请求,那直接用Guzzle的并发功能更轻量,不用折腾队列worker,在一个调度任务里就能搞定并行。

首先确保装了Guzzle:composer require guzzlehttp/guzzle

然后写一个自定义命令:

// app/Console/Commands/FetchAllApis.php
namespace App\Console\Commands;

use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use Illuminate\Console\Command;

class FetchAllApis extends Command
{
    protected $signature = 'fetch:all-apis';
    protected $description = '并行抓取所有API数据';

    public function handle()
    {
        $client = new Client();

        // 定义所有要发的请求
        $requests = function () {
            yield new Request('GET', 'https://api1.example.com/data'); // api1的接口
            yield new Request('GET', 'https://api2.example.com/data'); // api2的接口
            yield new Request('GET', 'https://api3.example.com/data'); // api3的接口
        };

        // 启动并发池
        $pool = new Pool($client, $requests(), [
            'concurrency' => 3, // 同时跑3个请求
            'fulfilled' => function ($response, $index) {
                // 处理每个请求的响应,存到数据库
                $data = json_decode($response->getBody(), true);
                // 根据索引判断是哪个API,调用对应的保存逻辑
                match($index) {
                    0 => (new \App\Classes\api1())->saveToDb($data),
                    1 => (new \App\Classes\api2())->saveToDb($data),
                    2 => (new \App\Classes\api3())->saveToDb($data),
                };
            },
            'rejected' => function ($reason, $index) {
                // 请求失败就记日志,方便排查
                \Log::error("第{$index}个API抓取失败: " . $reason->getMessage());
            },
        ]);

        // 等待所有请求完成
        $promise = $pool->promise();
        $promise->wait();

        $this->info('所有API抓取任务完成!');
    }
}

最后在调度器里注册这个命令:

protected function schedule(Schedule $schedule)
{
    $schedule->command('fetch:all-apis')->everyMinute();
}

方案三:PHP多进程(适合非HTTP的耗时任务)

如果你的fetch方法不是HTTP请求,而是比如本地数据处理、第三方SDK调用这类耗时操作,可以用PHP的pcntl扩展实现多进程并行。

直接在调度器里写逻辑就行:

protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        $processes = [];

        // 启动api1的进程
        $pid1 = pcntl_fork();
        if ($pid1 == 0) {
            (new \App\Classes\api1())->fetch();
            exit(); // 子进程执行完要退出
        } else {
            $processes[] = $pid1;
        }

        // 启动api2的进程
        $pid2 = pcntl_fork();
        if ($pid2 == 0) {
            (new \App\Classes\api2())->fetch();
            exit();
        } else {
            $processes[] = $pid2;
        }

        // 启动api3的进程
        $pid3 = pcntl_fork();
        if ($pid3 == 0) {
            (new \App\Classes\api3())->fetch();
            exit();
        } else {
            $processes[] = $pid3;
        }

        // 等待所有子进程结束
        foreach ($processes as $pid) {
            pcntl_waitpid($pid, $status);
        }
    })->everyMinute();
}

注意:这个方法需要服务器安装pcntl扩展,而且只能在CLI环境下运行(调度器本身就是CLI,所以没问题),但Web环境千万别用哦!

最后给你划个重点

  • 优先选队列方案:功能全、维护简单,完美适配长期调度的任务。
  • 如果是HTTP API,Guzzle并发更轻量,不用额外启动worker。
  • 多进程方案适合特殊场景,但需要扩展支持,维护成本稍高。

内容的提问来源于stack exchange,提问作者J.Adams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:22:58