请问下 Laravel 7 如果使用 Command 多线程?

$chapterDetail[‘img’],是远程同步图片地址,但是数据大约200W条 挨条处理是在太慢!服务器16H 32G 8T 硬件没有任何问题!请问下如何写多线程! 要不然200w条数据同步2个月时间太长了

  /*同步内容图片*/
        ini_set('memory_limit', '-1');
        foreach (ChapterDetail::all() as $chapterDetail)
        {
            if (strpos($chapterDetail['img'],'http://')===0 || strpos($chapterDetail['img'],'https://')===0)
            {
            $getChapterDetailPicUrlPicUrl = Http::get($chapterDetail['img'])->body();
                $chapterDetailPicUrl='/images/'.now()->timestamp.rand(000000000,999999999).'.jpg';
                Storage::disk('public')->put($chapterDetailPicUrl,$getChapterDetailPicUrlPicUrl);
                $chapterDetail->update(['img'=>'/storage/'.$chapterDetailPicUrl]);
            }
        }
        $this->info('全部图片同步完成');
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
最佳答案
$pids[];

collect(ChapterDetail::all())->chunk(10000)->each(function($chapterDetails) {
    switch ($pids[] = pcntl_fork()) {
        case -1:
           die('子进程创建失败!');
        case 0:
            foreach ($chapterDetails as $chapterDetail)
            {
                if (strpos($chapterDetail['img'],'http://')===0 || strpos($chapterDetail['img'],'https://')===0)
                {
                    $getChapterDetailPicUrlPicUrl = Http::get($chapterDetail['img'])->body();
                    $chapterDetailPicUrl='/images/'.now()->timestamp.rand(000000000,999999999).'.jpg';
                    Storage::disk('public')->put($chapterDetailPicUrl,$getChapterDetailPicUrlPicUrl);
                    $chapterDetail->update(['img'=>'/storage/'.$chapterDetailPicUrl]);
                }
            }
            exit;
        default:
            break;
    }
});

while (count($pids)) {
    $pid = pcntl_waitpid(-1, $status, WNOHANG);
    if ($pid === -1) {
        break;
    }
    $pids = array_filter($pids, fn($id) => $id !== $pid);
}

$this->info('全部图片同步完成');

pcntl_fork 方法只能在 cli 下运行

3年前 评论
yanthink (作者) 3年前
李小明 (楼主) 3年前
讨论数量: 11
$pids[];

collect(ChapterDetail::all())->chunk(10000)->each(function($chapterDetails) {
    switch ($pids[] = pcntl_fork()) {
        case -1:
           die('子进程创建失败!');
        case 0:
            foreach ($chapterDetails as $chapterDetail)
            {
                if (strpos($chapterDetail['img'],'http://')===0 || strpos($chapterDetail['img'],'https://')===0)
                {
                    $getChapterDetailPicUrlPicUrl = Http::get($chapterDetail['img'])->body();
                    $chapterDetailPicUrl='/images/'.now()->timestamp.rand(000000000,999999999).'.jpg';
                    Storage::disk('public')->put($chapterDetailPicUrl,$getChapterDetailPicUrlPicUrl);
                    $chapterDetail->update(['img'=>'/storage/'.$chapterDetailPicUrl]);
                }
            }
            exit;
        default:
            break;
    }
});

while (count($pids)) {
    $pid = pcntl_waitpid(-1, $status, WNOHANG);
    if ($pid === -1) {
        break;
    }
    $pids = array_filter($pids, fn($id) => $id !== $pid);
}

$this->info('全部图片同步完成');

pcntl_fork 方法只能在 cli 下运行

3年前 评论
yanthink (作者) 3年前
李小明 (楼主) 3年前

写个http接口,入参为同步的数组索引范围。然后用Java(Thread+HttpClient)或者php(curl_multi)写个多线程接口调用,模拟100个并发线程即可。 本身宿主机若用php-fpm,需要开启100个以上的子进程。

3年前 评论
李小明 (楼主) 3年前
蔺焕然

填入队列中 走消费模型

3年前 评论
gooogle 3年前
yanthink 3年前
Epona

这种功能都是走队列的,而不是走多线程

3年前 评论

file

3年前 评论

简单粗暴

php arstian spider
php arstian spider
php arstian spider
php arstian spider
.......
3年前 评论
李小明 (楼主) 3年前
小李世界 (作者) 3年前

应该不能叫多线程,可启动多个队列,进行多进程消费。

3年前 评论

外层foreach写成ScheduleJob负责遍历调度,foreach 内部代码写成WorkJob负责处理工作,设置一下连接超时时间。horizon开20个进程就差不多了。

3年前 评论
$pids[];

collect(ChapterDetail::all())->chunk(10000)->each(function($chapterDetails) {
    switch ($pids[] = pcntl_fork()) {
        case -1:
           die('子进程创建失败!');
        case 0:
            foreach ($chapterDetails as $chapterDetail)
            {
                if (strpos($chapterDetail['img'],'http://')===0 || strpos($chapterDetail['img'],'https://')===0)
                {
                    $getChapterDetailPicUrlPicUrl = Http::get($chapterDetail['img'])->body();
                    $chapterDetailPicUrl='/images/'.now()->timestamp.rand(000000000,999999999).'.jpg';
                    Storage::disk('public')->put($chapterDetailPicUrl,$getChapterDetailPicUrlPicUrl);
                    $chapterDetail->update(['img'=>'/storage/'.$chapterDetailPicUrl]);
                }
            }
            exit;
        default:
            break;
    }
});

while (count($pids)) {
    $pid = pcntl_waitpid(-1, $status, WNOHANG);
    if ($pid === -1) {
        break;
    }
    $pids = array_filter($pids, fn($id) => $id !== $pid);
}

$this->info('全部图片同步完成');

pcntl_fork 方法只能在 cli 下运行

3年前 评论
yanthink (作者) 3年前
李小明 (楼主) 3年前

队列,用supervisor管理队列,可以支持多进程

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!