请问下 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('全部图片同步完成');
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案
$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年前
$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年前
蔺焕然

填入队列中 走消费模型

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

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

3年前 评论
李小明 (楼主) 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年前 评论

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

3年前 评论

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