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

Laravel批量二维码生成性能优化求助:单次生成100个耗时2分钟

问题描述

我正在用Laravel开发一套系统,用户可以通过输入框输入数量来生成对应数量的二维码。测试时单次生成100个二维码耗时近2分钟,请问怎么尽可能提升生成速度?感谢帮助!

控制器中的StoreQR方法:

public function storeQR(Request $request)
{
    $numberOfDevices = (int) $request->input('number');
    if ($numberOfDevices <= 0) {
        return back()->withErrors(['number' => '请输入有效的设备数量。']);
    }

    for ($i = 0; $i < $numberOfDevices; $i++) {
        $deviceID = Str::random(8);

        // 创建设备数据
        $devices[] = [
            'deviceId' => $deviceID,
        ];
    }

    GenerateQRJob::dispatch($devices);

    return to_route('devices.index');
}

GenerateQRJob任务类:

public function __construct($devices)
{
    $this->devices = $devices;
}

/**
 * 执行任务
 */
public function handle(): void
{
    $devices = [];
    foreach ($this->devices as $device){
        // 生成二维码和路径
        $qr = QrCode::format('png')
        ->size(285)
        ->generate(route('devices.qr', $device['deviceId']));
        $path = 'img/qr-codes/' . $device['deviceId'] . '.png';
        Storage::disk('public')->put($path, $qr);

        $devices[] = [
            'deviceId' => $device['deviceId'],
            'barcode' => $path
        ];
    }
    DB::table('devices')->insert($devices);
}

优化方案

1. 拆分任务为多个子任务并行处理

当前所有设备数据都塞进单个队列任务串行处理,改成按固定数量分块,每个块单独触发一个任务,利用队列多进程并行执行,能大幅压缩总耗时。

修改控制器storeQR方法:

public function storeQR(Request $request)
{
    $numberOfDevices = (int) $request->input('number');
    if ($numberOfDevices <= 0) {
        return back()->withErrors(['number' => '请输入有效的设备数量。']);
    }

    // 每10个设备拆成一个任务,可根据服务器性能调整分块大小
    collect(range(1, $numberOfDevices))->chunk(10)->each(function ($chunk) {
        $devices = $chunk->map(function () {
            return [
                'deviceId' => Str::random(8),
            ];
        })->toArray();

        GenerateQRJob::dispatch($devices);
    });

    return to_route('devices.index');
}

注意:启动队列时要开启多个worker进程,比如执行php artisan queue:work --processes=5,让多个任务能同时运行。

2. 替换二维码生成工具为系统命令行工具

PHP原生二维码库的生成速度较慢,换成系统级的qrencode工具,生成效率会提升数倍。

首先安装qrencode:

  • Ubuntu/Debian:sudo apt-get install qrencode
  • CentOS/RHEL:sudo yum install qrencode

修改任务类handle方法:

public function handle(): void
{
    $devices = [];
    // 预先生成路由基础地址,避免重复调用route函数解析路由
    $baseQrUrl = url('/devices/qr/');
    $storagePath = storage_path('app/public/img/qr-codes/');
    
    // 确保目录存在,避免生成失败
    if (!File::exists($storagePath)) {
        File::makeDirectory($storagePath, 0755, true);
    }

    foreach ($this->devices as $device) {
        $deviceId = $device['deviceId'];
        $qrContent = $baseQrUrl . $deviceId;
        $filePath = $storagePath . $deviceId . '.png';

        // 调用系统命令生成二维码,-s参数控制尺寸(对应原size(285))
        exec("qrencode -s 10 -o {$filePath} '{$qrContent}'");

        $devices[] = [
            'deviceId' => $deviceId,
            'barcode' => 'img/qr-codes/' . $deviceId . '.png'
        ];
    }

    DB::table('devices')->insert($devices);
}

3. 减少路由解析开销

原代码每次生成二维码都调用route()函数解析路由,换成直接拼接URL的方式,避免重复的路由解析计算,上面的代码已经包含这个优化。

4. 优化文件存储逻辑

直接通过系统命令写入文件,跳过Laravel Storage的封装层,减少IO操作的额外开销;同时提前检查并创建目录,避免每次写入时的目录检查耗时。

5. 配置任务超时时间

在GenerateQRJob类中添加超时配置,避免单个任务因耗时过长被队列终止:

class GenerateQRJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $timeout = 60; // 单个任务超时时间,单位秒
    // ... 其他代码
}

内容的提问来源于stack exchange,提问作者rizkydhani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:59:58