php通过 pcntl_fork 进行异步发送任务的失败示例

php的异步背景说明:

php的fpm模式没有很好的异步请求方案,常见的fsocketopen也是“伪异步“,可能在不知道什么场景下就会失效而不自知,因此用到正式环境是很危险的。

而php开发者又不想单独在cli模式跑一套swoole等等这样的任务处理后台,因为这样增加了维护成本等

因此本人想到可以使用pcntl_fork实现进程级别的异步,这种做法牺牲了系统资源,带来了速度提升,在非重度邮件发送等这种场景较为适用。但是无奈,用到正式环境后发现短时间内有大量的进程堆积而不自动退出,造成内存被大量占用,同时这些进程又非处于僵死态,因此很费解,因为按照个人理解,主进程退出,衍生的子进程也会自动退出。

代码如下:

环境评论区评论指正


/**
 * 异步请求
 * 
 * pcntl_fork 实现 
 * 
 * Linux操作系统才可用
 * 
 * 优点为 稳定、节约时间
 * 确定为 增加了系统的资源消耗
 * 
 * 本质为开启一个后台子进程来处理耗时操作而主进程可立即响应用户
 *
 * @param string $url
 * @param string $type
 * @param array $fields
 * @param boolean $unescaped
 * @return void
 */
function funCurlRequestAsync_v2($url, $type = 'POST', $fields = [], $unescaped = false)
{
    // 创建子进程
    $pid = pcntl_fork();

    if ($pid == -1) {
        // 创建子进程失败
        exit();
    } elseif ($pid == 0) {

        //初始化
        $curl = curl_init();

        //设置请求url
        curl_setopt($curl, CURLOPT_URL, $url);

        //设置true会将头文件的信息作为数据流输出 否则作为字符串输出
        curl_setopt($curl, CURLOPT_HEADER, false);

        //设置true会不输出body部分 此时请求类型被转变为head请求
        curl_setopt($curl, CURLOPT_NOBODY, false);

        //设置true会将curl_exec()获取的信息以字符串返回 否则会直接输出
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        //设置true会在页面发生301或者302时自动进行跳转抓取
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

        //如果将请求类型改为get 如果为探测状态 可避免因为请求类型为head造成的探测失误
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $type);

        //设置请求超时时间
        curl_setopt($curl, CURLOPT_TIMEOUT, 600);

        //设置false将不检查证书
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        //设置false将不检查证书
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

        /**
         * 配置表单信息
         */

        //携带数据为一维数组
        // if (!empty($fields)) {
        //     curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($fields));
        // }

        //携带数据为json
        if (!empty($fields)) {
            if ($unescaped) {
                $fields  = json_encode($fields, JSON_UNESCAPED_UNICODE);
            } else {
                $fields  = json_encode($fields);
            }
            curl_setopt($curl, CURLOPT_POSTFIELDS, $fields);
        }

        //执行
        $result = curl_exec($curl);

        //关闭
        curl_close($curl);

        // return $result;

        // 子进程执行完毕后退出
        exit();
    } else {
        // 父进程继续执行,可以立即返回响应给用户
        return ['error_code' => 0];
    }
}

原创文章,作者:witersen,如若转载,请注明出处:https://www.witersen.com

(0)
witersen的头像witersen
上一篇 2023年9月16日 上午3:07
下一篇 2023年9月16日 上午3:28

相关推荐

发表回复

登录后才能评论