在做项目中,经常遇到比如说要发送邮件或者短信验证码,或者导出任务等比较耗时的任务,采用同步方式就可能用户需要等待了,体验不友好,为了缩短用户等待时间,这时可以采用异步的方式,比如消息队列等,我想到一个小方法,去触一个脚本去执行,php的exec函数能执行linux命令,可以用来执行脚本,但是经过测试,发现程序还是要等待脚本执行完毕才返回。于是就想到了popen

定义和用法

popen() 函数打开进程文件指针。

语法

popen(command,mode)

参数 描述

command 必需。规定要执行的命令。

mode 必需。规定连接模式。 可能的值:

r: 只读。

w: 只写 (打开并清空已有文件或创建一个新文件)

说明

打开一个指向进程的管道,该进程由派生指定的 command 命令执行而产生。

返回一个和 fopen() 所返回的相同的文件指针,只不过它是单向的(只能用于读或写)并且必须用 pclose() 来关闭。此指针可以用于 fgets(),fgetss() 和 fwrite()。

若出错,则返回 false。

可以使用popen去执行一些命令,还不会等待

接下来做个小实验:

目录结构:

BaAGeedeMacBook-Pro:async_test dangliuhui$ tree
.
├── AsyncTask.php
├── script
│   └── test_1.php
├── task_map_config.php
└── test.php
AsyncTask.php为任务主要类:
class AsyncTask
{
    protected static $map = [];

    public static function run($script_name, $data = [])
    {
        self::$map = include_once './task_map_config.php';

        $script_path = self::getTask($script_name);
        $where = '';

        foreach ($data as $k => $v) {
            $where .= ' --' . $k . '=' . $v;
        }
        $command = PHP_BINARY . ' ' . $script_path . $where . ' &';
        $handle = popen($command, 'w');
        pclose($handle);
        return $where;
    }

    public static function getTask($script_name)
    {
        return self::$map[$script_name];
    }
}
task_map_config.php主要配置了任务名称和其对应的脚本路径:
return [
//    'task_name'=>'script_path'
    'test_1' => __DIR__ . '/script/test_1.php'
];
接下来编写脚本文件(script/test_1.php):
echo '脚本开始运行' . PHP_EOL;
$s_t = microtime(true);
$fields = [
    'name:',
    'age:',
    'aaa:',
    'bbb:',
    'ccc:',
];
//php cli模式下接收脚本参数
$where = getopt('', $fields);

var_dump('接收到的参数:' . json_encode($where, JSON_UNESCAPED_UNICODE));
foreach ($where as $k => $v) {
    echo sprintf('%s=>%s', $k, $v) . PHP_EOL;
    sleep(1);
}

$e_t = microtime(true);
echo '脚本执行结束,运行时间:' . ($e_t - $s_t);

其实很简单,模拟耗时操作,打印接收变量值

解析来就是怎么去调用这个脚本,异步执行了。

test.php为测试文件:

include './AsyncTask.php';

//test
$data = [
    'name' => 'hahha哈哈哈',
    'age' => 123,
    'aaa' => 'jkhgf9876',
    'bbb' => 'bbbbb',
    'ccc' => 'ccccccc',
];

echo 'start' . PHP_EOL;
echo AsyncTask::run('test_1', $data) . PHP_EOL;
echo 'end' . PHP_EOL . PHP_EOL;

直接AsyncTask::run('任务名','脚本所需参数数组');就可以啦

查看输出结果:

start
 --name=hahha哈哈哈 --age=123 --aaa=jkhgf9876 --bbb=bbbbb --ccc=ccccccc
end

脚本开始运行
string(106) "接收到的参数:{"name":"hahha哈哈哈","age":"123","aaa":"jkhgf9876","bbb":"bbbbb","ccc":"ccccccc"}"
name=>hahha哈哈哈
age=>123
aaa=>jkhgf9876
bbb=>bbbbb
ccc=>ccccccc
脚本执行结束,运行时间:5.0003838539124
Process finished with exit code 0

可以很明显的看出虽然test.php早早的已经执行完毕,但是耗时的tet_1脚本还在继续执行,这样就实现了异步处理。

里面的细节比如popen详情,php cli模式下获取参数等你可以google一下具体资料。

相关评论(0)
您是不是忘了说点什么?

友情提示:垃圾评论一律封号...

还没有评论,快来抢沙发吧!