本篇文章给大家带来的内容是关于php为什么需要异步编程?php异步编程的详解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
我对 php 异步的知识还比较混乱,写这篇是为了整理,可能有错。
传统的 php-fpm 一个进程执行一个请求,要达到多少并发,就要生成多少个进程。更糟糕的是每次请求都需要重新编译执行,导致并发一直上不来。因此出现了 swoole 和 workerman 两个国内流行的常驻内存框架[1]。这两个框架原理都是通过事件循环,让程序一直停留在内存,等待外部请求,达到高并发。
为什么需要异步
先来看一个例子
在工作目录下新建文件 slowrver.php
1
2
3
<?php
sleep(5);
// 5秒后才能返回请求
echo
'done'
;
开启服务迫不及待的反义词
1
$ php -s localhost:8081 slowrver.php
开另一个终端,安装依赖
1
2
3
$ pecl install event # 安装 event 扩展
$ compor
require
workerman/workerman
$ compor
require
react/http-client:^0.5.9
新建文件 worker.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require_once
__dir__ .
'/vendor/autoload.php'
;
u
workerman\worker;
u
workerman\connection\asynctcpconnection;
u
amp\artax\respon;
$http_worker
=
new
worker(
"http://0.0.0.0:8082"
);
$http_worker
->
count
= 1;
// 只开一个进程
$http_worker
->onmessage =
function
(
$connection
,
$host
) {
echo
1;
$data
=
file_get_contents
(
'http://localhost:8081'
);
$connection
->nd(
$data
);
};
worker::runall();
开启服务器
1
php worker.php start
在浏览器开启两个标签,都打开网址 http://localhost:8082 。这时可以看到终端输出“1”,过了一会儿又输出“1”,原因是8081服务器在处理第一个请求的时候阻塞在了等待8081返回之中,等第一个请求结束后,才开始处理第二个请求。也就是说请求是一个一个执行的,要达到多少个并发,就要建立多少个进程,跟 php-fpm 一样。现在修改一下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$http_worker
->onmessage = 港澳留学
function
(
$connection
,
$host
) {
echo
1;
$loop
= worker::geteventloop();
$client
=
new
\react\httpclient\client(
$loop
);
$request
=
$client
->request(
'get'
,
'http://localhost:8081'
);
$request
->on(
'error'
,
function
(exception
$e
)
u
(
$connection
) {
$connection
->nd(
$e
);
});
$request
->on(
'respon'
,
function
(
$respon
)
u
(
$connection
) {
$respon
->on(
'data'
,
function
(
$data
)
u
(
$connection
) {
$connection
->nd(
$data
);
});
});
$request
->
end
();
};
现在打开服务,再在浏览器发起请求,发现第二个“1”在请求后就马上输出了,而这时第一个请求还没结束。这表明进程不再阻塞,并发量取决于 cpu 和 内存,而不是进程数。
为什么需要异步
通过上面的例子已经很明白了,reactphp 框架通过把 http 请求变成异步,让 onmessage 函数变成非阻塞,cpu 可以去处理下一个请求。即从 cpu 循环等待 8081 返回,变成了 epoll 等待。
异步的意义在于把 cpu 从 io 等待中解放出来,可以处理其他计算任务。如果你想知道怎么用框架实现异步,看到这里就可以了。workerman 配合 reactphp 或者自身的 asynctcpconnection 已经可以满足很多 io 请求异步化的需求。下面继续讨论这些框架是怎么做到异步的。
哪些地方应该被做成异步
通过上面的例子已经知道一旦执行到不需要 cpu,但是要等待 io 的时候,应该把 io 的过程做成异步。
实现事件循环
上面的例子是通过 reactphp 把 http 请求变成了异步,其实 workerman 框架本身也是异步的,下面来看看 workerman 是怎么使 onm西安楼观台essage 函数可以异步接受请求。先来新建下面这个文件 react.php
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$context
= stream_context_create();
$socket
= stream_socket_rver(
'tcp://0.0.0.0:8081'
,
$errno
,
$errmsg
, stream_rver_bind | stream_rver_listen,
$context
); // 注册一个 fd(file descriptor)
function
react(
$socket
){
$new_socket
= stream_socket_accept(
$socket
, 0,
$remote_address
);
5452830
echo
1;
}
$eventba
=
new
eventba();
$event
=
new
event(
$eventba
,
$socket
, event::read | event::persist,
'react'
,
$socket
);
// 注册一个事件,检测 fd 有没有写入内容
$event
->add();
$eventba
->loop();
// 开始循环
开始执行
1
$ php react.php
在另一个终端执行
1
telnet 127.0.0.1 8081
这时就会看到第一个终端输出’1’。
我之前写过一篇文章《php使用epoll》,是这篇文章的基础。那篇文章里事件回调是通过定时来实现,即
1
$event
->add(
$conds
);
而这里,事件回调是通过检测 fd 是否有写入内容来实现,这个过程不需要 cpu 参与。当 fd 有内容写入时,会调函数 ‘react’,这时开始使用 cpu。如果这时候进程执行另一个异步请求,比如用 reactphp 框架请求一个网页,那么程序会让出 cpu,此时如果有另一个请求进来,就可以回调执行另一个 ‘react’ 函数。由此提高了并发量。
协程
生成器 generater
这是母亲英语怎么读生成器的 php 官方文档 http://php.net/manual/zh/lang…
1
2
3
4
5
6
7
8
9
10
11
12
<?php
function
gen_one_to_three() {
for
(
$i
= 1;
$i
<= 3;
$i
++) {
//注意变量$i的值在不同的yield之间是保持传递的。
yield
$i
;
}
}
$generator
= gen_one_to_three();
foreach
(
$generator
as
$value
) {
echo
"$value\n"
;
}
生成器就是每次程序执行到 yield 的时候保存状态,然后返回 $i,是否继续执行 gen_one_to_three 里的循环,取决于主程序是否继续调用
什么是协程
上面的程序另一种写法是
1
2
3
4
5
6
7
8
9
10
11
12
<?php
$i
= 1;
function
gen_one_to_three() {
global
$i
;
if
(
$i
<=3){
return
$i
++;
}
}
while
(
$value
= gen_one_to_three()) {
echo
"$value\n"
;
}
由此可见,协程就是一种对函数的封装,使其变成一种可以被中断的函数,行为更像是子进程或子线程,而不是函数。协程的具体写法这里不细写,因为协程的写法十分复杂,可能需要再做一层封装才能好用。
协程与异步
既然协程可以被中断,那么只要在程序发起请求后发起事件循环,然后用 yield 返回,然后程序继续执行主程序部分,等事件返回后触发函数,执行 generatot::next() 或 generator::nd() 来继续执行协程部分。封装好后就好像没有异步回调函数一样,和同步函数很像。
现在已经有 ampphp 和 swoole 两个框架封装了协程,有兴趣可以了解一下。
本文发布于:2023-04-07 20:17:22,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/087086324fbd43018d3767f856975ce7.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:php为什么需要异步编程?php异步编程的详解(附示例).doc
本文 PDF 下载地址:php为什么需要异步编程?php异步编程的详解(附示例).pdf
留言与评论(共有 0 条评论) |