V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
abccccabc
V2EX  ›  PHP

各路 PHP 高手,谁用过 PHP 的并发?是指 composer 里的工具包

  •  
  •   abccccabc · 286 天前 · 2812 次点击
    这是一个创建于 286 天前的主题,其中的信息可能已经有所发展或是发生改变。
    各路 PHP 高手,谁用过 PHP 的并发?主要是 composer 里的工具包,并不是指 swoole 。

    目的:用于获取 web 图片
    使用场景:复制一篇经典的文章到我自己的论坛,可能含有图片 20 张左右,如果使用 curl 一张一张的取,网络不好的时候可能会超时,如果图片更多,绝对超时;如果用并发 curl 取图片,应该会很快。

    希望此 composer 包能兼容的 php 版本多些。
    37 条回复    2024-04-18 11:24:18 +08:00
    shiny
        1
    shiny  
       286 天前
    不试试 curl_multi_exec ?
    a282810
        2
    a282810  
       286 天前
    simonlu9
        3
    simonlu9  
       286 天前   ❤️ 1
    pthread 试下
    huyiwei
        4
    huyiwei  
       286 天前
    多开几个进程呗
    a282810
        5
    a282810  
       286 天前
    wonderfulcxm
        6
    wonderfulcxm  
       286 天前 via iPhone
    guzzle 就可以
    abccccabc
        7
    abccccabc  
    OP
       286 天前
    ```
    @a282810
    以前爬东西用过 https://github.com/ares333/php-curl
    ```
    简单看了一下使用示例,并没有看到并发的相关操作。而且此包很久都没有更新了。处于无维护状态。
    panlatent
        8
    panlatent  
       286 天前
    用 curl 拓展或者 Guzzle 库,推荐后者, 尽量不要尝试多进场/线程方案,坑太多。
    k9982874
        9
    k9982874  
       286 天前 via Android
    php 现在能并发了?牛!另外爬东西不试试 py ?
    vacker
        10
    vacker  
       286 天前 via iPhone
    我选择使用队列
    hefish
        11
    hefish  
       286 天前
    这思路不对啊,这不是应该往异步方面去考虑吗?怎么硬往并发上去凑?
    a282810
        12
    a282810  
       286 天前
    @abccccabc #7 其实是基于 curl_multi_exec , 能实现需要的功能就可以了,Curl::add()添加任务到任务池,Curl::start()开始执行任务并阻塞
    abccccabc
        13
    abccccabc  
    OP
       286 天前
    @k9982874 不是做爬虫,是复制 web 文章到我的论坛,同时要将图片进行本地化。而且还要替换掉内容中的外部图片地址。

    @a282810 https://github.com/ares333/php-curl 这个项目里感觉更像异步,并发的话,肯定还要处理后续事情。他的项目示例里没有体现出来。


    我是复制一些网络上优秀的文章到 dz 论坛,同时需要替换掉文章内容对应的 bbcode 图片代码。异步真不知道怎么操作,并发的话,我知道后续会有一个结果,对这个结果 foreach 就可以得到下载后图片。方便处理后续替换入库等操作。
    abccccabc
        14
    abccccabc  
    OP
       286 天前
    @a282810 要求 php7.1 以上的 https://github.com/Yurunsoft/YurunHttp

    这个工具包可以研究研究,它的低版本可以考虑。谢谢
    k9982874
        15
    k9982874  
       286 天前 via Android
    @abccccabc 你说的不就是爬虫,白嫖就白嫖大方承认不丢人,强行解释就又当又立了
    abccccabc
        16
    abccccabc  
    OP
       286 天前
    @k9982874 没玩过爬虫,我是手工复制文章到论坛。有时候因为文章的图片太多,导致图片本地化失败。到目前为止,还没有自动采集过别人的文章入数据库的事情。

    白嫖???工具包我只能白嫖呀,像这样的工具包 Yurunsoft/YurunHttp 我写不出来的,只能用别人写好的工具包。
    UFc8704I4Bv63gy2
        17
    UFc8704I4Bv63gy2  
       286 天前
    帖子保存起来然后异步去下载图片,什么年代了还同步取图
    并发取图 curl_multi_exec 推荐,pthread 不推荐坑多
    wpjscc
        18
    wpjscc  
       286 天前 via Android
    异步可以试试 reactphp http

    https://github.com/reactphp/http
    abccccabc
        19
    abccccabc  
    OP
       286 天前
    沃得天呐,你们到底知道多少这种 PHP 工具包呀?

    看来是我见识少呀,向各路并发/异步 PHP 高手学习学习。展示一下你写的 并发/async php 代码???让我开开眼界呗。
    erquiasz0825
        20
    erquiasz0825  
       285 天前
    guzzle 简单好用,默认也是用 curl_multi_exec ,不是多线程也不是多进程,而是用非阻塞 I/O 的原理。
    lasuar
        21
    lasuar  
       285 天前
    最近发现的一条 curl 并发命令写法(8 个并发):
    seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code}&'
    lasuar
        22
    lasuar  
       285 天前
    seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code} &'
    abccccabc
        23
    abccccabc  
    OP
       285 天前
    @erquiasz0825 guzzle 简单好用,默认也是用 curl_multi_exec ,不是多线程也不是多进程,而是用非阻塞 I/O 的原理。

    楼上有人建议过,我看了下,他的版本让人真的好纠结:用 v6 版本 php 版本为 >=5.5 and <8.0 ,用 v7 版本, php >= 7.2.5 。

    现在在看 Yurunsoft/YurunHttp
    ben1024
        25
    ben1024  
       285 天前
    guzzle ,reactphp 都可以,curl_multi_exec 原生也可以
    zzzyyysss
        26
    zzzyyysss  
       285 天前
    这种就该在前端用 js 处理,你的 php 只需要一个上传的接口,前端把图拿出来 然后一个个直接传给 php ,php 返回保存在服务器的地址,然后你再前端用 js 把原来的地址替换,然后保存就 ok
    liaoxx
        27
    liaoxx  
       285 天前
    有幸写过一个用 yeild 和 guzzle/http 的请求池写过一个工具类
    /**
    * 异步/并发/批量请求 (慎用)
    * @param string $url 请求地址
    * @param array $allParams 所有请求参数 int[{once request params}]
    * @param array $options 请求配置 ['headers'=>[]]
    * @param callable|null $onSuccess 请求成功回调函数 function(ResponseInterface $response,int $index,array $params){}
    * @param callable|null $onFailure 请求失败回调函数 function(\Exception $exception,int $index,array $params){}
    * @param callable|null $onComplete 请求完成回调函数
    * @return void
    * @author LiaoYongjian
    * @date 2024-01-19 17:43
    */
    public function postAsyncRequests(string $url, array $allParams, array $options = [], callable $onSuccess = null, callable $onFailure = null, callable $onComplete = null)
    {
    $headers = $options['headers'] ?? [];
    $client = $this->getCli();

    //生成器 用于生成异步请求
    $generator = function () use ($client, $allParams, $url, $headers, $onSuccess, $onFailure) {
    foreach ($allParams as $index => $params) {
    yield function () use ($client, $url, $headers, $index, $params, $onSuccess, $onFailure) {
    //异步请求
    return $client->postAsync($url, [
    'headers' => $headers,
    'json' => $params,
    ])->then(
    function ($response) use ($onSuccess, $index, $params) {
    if ($onSuccess) {
    $onSuccess($response, $index, $params);
    }
    return $response;
    },
    function (\Exception $e) use ($onFailure, $index, $params) {
    if ($onFailure) {
    $onFailure($e, $index, $params);
    }
    throw $e;
    }
    );
    };
    }
    };
    //异步请求池
    $pool = new Pool($client, $generator());
    //异步请求池的回调函数
    $responses = $pool->promise()->wait();
    if ($onComplete){
    $onComplete($responses);
    }
    }
    cybort
        28
    cybort  
       285 天前 via Android
    超时是给你限流了吧,你请求的快限的更快。
    putyy
        29
    putyy  
       285 天前
    原生 curl_multi
    putyy
        30
    putyy  
       285 天前
    如果资源存的七牛 还可以用七牛云的接口帮下载
    abccccabc
        31
    abccccabc  
    OP
       285 天前
    @zzzyyysss

    你说的是这样的吗?
    ```
    var allimg = 获取到的图片数组;
    var oldcontent = 原内容;
    for(var i=0; i<allimg.length; i++){
    $.post('url', 参数, function(ret) {
    if(ret['code'] == 200) {
    oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl']);
    }else{
    console.log(错误信息);
    }
    }, 'json');
    }
    ```

    这样有一个很大的问题:多个异步去修改同一全局变量,必须要锁定全局变量 oldcontent ,然后用队列的形式去替换 oldcontent 内容,不然最后只会有一个修改 oldcontent 生效。

    这样更麻烦,搞不定。

    -------------------
    php 用了并发,现在问题也不小,
    ```
    <?xml version="1.0" encoding="UTF-8"?>
    <Error>
    <Code>AccessDenied</Code>
    <Message>You are denied by bucket referer policy.</Message>
    <RequestId>65F44FE6D4BE2035341DF46B</RequestId>
    <HostId>40114.oss-cn-beijing.aliyuncs.com</HostId>
    <BucketName>blog-picture-240114</BucketName>
    <EC>0003-00000503</EC>
    <RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000503</RecommendDoc>
    </Error>
    ```
    这节奏似乎只能放弃 PHP 并发了。
    abccccabc
        32
    abccccabc  
    OP
       285 天前
    @putyy 用不起云存储,个人小论坛,用来记录我的学习而已。

    @cybort 确实是并发超过一定数量后,部分主机会限制。直接返回类似 403 这种
    zzzyyysss
        33
    zzzyyysss  
       285 天前
    你为什么要锁定全局变量,你的目标不就是 源代码中的 图片地址远程换本地吗?
    你可以在任何时间点 处理这个操作。
    js 那个方法 你只要在上传完毕之后,用最新的地址 从富文本中替换旧地址就可以了。
    或者你在点击保存按钮之后加个 loading 统一处理。
    之所以推荐你在前端处理是因为有些网站你用后台 php 去抓图片会有防盗链的。
    abccccabc
        34
    abccccabc  
    OP
       285 天前
    @zzzyyysss 我试过了,多个异步去修改 oldcontent 替换旧图片地址,只有 for 循环最后 i 变量替换操作生效。 现在我明白,是要对 oldcontent 加锁,这应该就是竞争。太深澳了,又搞不定。唉。


    看来现在得请教 JS 高手了。
    zzzyyysss
        35
    zzzyyysss  
       284 天前
    ```
    const images = [];
    const replaceData = {};
    const asyncPost = (url, data) => {
    return new Promise((resolve, reject) => {
    $.post(url, data, (ret) => {
    if(ret['code'] == 200) {
    resolve(ret);
    } else {
    reject('获取图片出错')
    }
    })
    })
    }
    // 每当拿到新的图片时调用
    const onNewImage = async (oldImgUrl) => {
    if (!replaceData[oldImgUrl]) {
    const ret = await asyncPost(url, data);
    replectData[ret['oldImgUrl']] = ret['newImgUrl'];
    }
    }
    // 在保存之前 处理 content
    const beforeSubmit = (content) => {
    Object.keys.forEach(oldUrl => {
    content.replaceAll(oldUrl, replaceData[newUrl])
    })
    return content;
    }
    ```
    大概就是这样,你可以试试
    alex8
        36
    alex8  
       270 天前
    没有稳定的原生解决方案, 上层的 composer 里更不会有。
    lyxxxh2
        37
    lyxxxh2  
       253 天前
    guzzlephp 就有啊,文档都写着...
    官方 curl 也有,更麻烦。

    https://docs.guzzlephp.org/en/stable/quickstart.html
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2800 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 02:54 · PVG 10:54 · LAX 18:54 · JFK 21:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.