请问下 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 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 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 下运行

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

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

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

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

填入队列中 走消费模型

1年前 评论
gooogle 1年前
yanthink 1年前
wade 1年前
Epona

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

1年前 评论

file

1年前 评论

简单粗暴

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

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

1年前 评论

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

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

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

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

1年前 评论

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