请问下 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('全部图片同步完成');
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案
$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 下运行

4年前 评论
pingfan (作者) 4年前
李小明 (楼主) 4年前
讨论数量: 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 下运行

4年前 评论
pingfan (作者) 4年前
李小明 (楼主) 4年前

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

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

填入队列中 走消费模型

4年前 评论
gooogle 4年前
pingfan 4年前
Epona

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

4年前 评论

file

4年前 评论

简单粗暴

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

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

4年前 评论

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

4年前 评论
$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 下运行

4年前 评论
pingfan (作者) 4年前
李小明 (楼主) 4年前

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

4年前 评论

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