生活的案例理解epoll , event loop 协程
协程可以简单理解为线程,只不过这个线程是用户态的,不需要操作系统参与,创建销毁和切换的成本非常低,和线程不同的是协程没法利用多核 CPU 的,想利用多核 CPU 需要依赖
Swoole的多进程模型。
案例1:
假设你是一个饭店的服务员,你需要同时为多桌客人服务。每桌客人都有自己的需求,有的需要点菜、有的需要加水、有的需要结账等。你不能只为一桌客人服务,而是需要不断地切换服务,让每桌客人的需求都得到满足。
Event Loop 就像是你的服务调度系统,它会不断地扫描客人的需求,根据需求类型和状态来调度你的服务。如果某桌客人需要点菜,你就会立即前往该桌进行服务,然后将该桌的需求状态标记为“等待”,等待客人点完菜后再次触发服务。如果某桌客人需要加水,你也会立即前往该桌进行服务,然后将该桌的需求状态标记为“等待”,等待客人再次需要加水时触发服务。
如果一桌客人需要等待烹饪,那么你就可以在等待的时间内前往其他桌进行服务,这样可以最大限度地利用你的时间和资源,提高服务效率。
在这个例子中,你就是一个协程,多桌客人就是多个协程,服务调度系统就是 Event Loop。Event Loop 会不断地监听各个协程的状态,然后根据状态来调度协程的执行,从而实现多个协程之间的并发执行。
案例2:
为什么 如果一个协程一直被阻塞,那么它就无法继续执行下去,同时也不能切换出去运行其他协程。(协程调度器)
我们可以把 Event Loop 理解为一个类似于舞台上的导演,而协程就像是演员。
假设有一台话剧正在上演,舞台上有多个演员在表演各自的角色。导演需要不断地指挥演员们的表演,同时要处理现场突发情况,比如说灯光故障、音响出问题等等。
在这个过程中,如果某个演员出现了问题,比如说忘记台词或者身体不适,就会影响整个表演的进度。导演不能让这个演员一直占据舞台,而是需要及时处理这个问题,并找到其他演员替代他的角色。(堵塞)
同样地,如果一个协程在执行过程中被阻塞,比如说等待 I/O 操作完成,那么它就无法继续执行下去。由于 Event Loop 是单线程的,不能同时执行多个协程,因此这个阻塞的协程就会一直占据着 Event Loop 的执行资源,其他协程就无法得到执行。这就像导演不能让某个演员一直占据舞台一样,影响了整个表演的进度和效果。
因此,在编写协程时,需要尽可能地避免阻塞操作,比如说使用异步 I/O 或者非阻塞操作,从而最大限度地利用 Event Loop 的执行资源,提高程序的并发能力和效率。
那么如何才能保证协程里面的程序不被堵塞
- 使用异步 I/O:异步 I/O 可以让 I/O 操作在后台执行,而不会阻塞协程的执行。常见的异步 I/O 库有 asyncio、Tornado 和 Twisted 等。
- 使用非阻塞操作:非阻塞操作是指在执行某个操作时,不会一直等待其结果返回,而是会立即返回一个结果,无论该结果是成功的还是失败的。常见的非阻塞操作包括非阻塞的网络套接字和文件句柄等。
- 使用协程并发框架:协程并发框架可以让多个协程同时执行,并通过调度器控制其执行顺序和并发度,从而最大限度地利用 CPU 和 I/O 资源。
- 使用多线程或进程:如果必须使用阻塞操作,可以考虑使用多线程或进程来避免阻塞协程的执行。这种方式需要注意线程或进程间的同步和通信问题,以避免出现数据竞争和死锁等问题。
则PHP中的Swoole采用 Hook 原生 PHP 函数的方式实现协程客户端 这里解释一下HOOK
白话文
记录当前程序 执行到的一个步骤和状态 接着执行
官方的说法
在计算机编程中,“Hook”是指在运行时改变或扩展软件系统行为的技术。在 PHP 中,Hook 可以用来截获函数调用,修改函数的参数或返回值,或者在函数调用前后执行额外的代码。
Hook 代码解释
function my_strtoupper($str) {
// 在原始函数调用前执行额外的代码
echo "Calling strtoupper() with parameter: $str\n";
// 调用原始函数,并修改返回值
$result = strtoupper($str) . " from my_strtoupper()";
// 在原始函数调用后执行额外的代码
echo "strtoupper() returned: $result\n";
return $result;
}
// 将原始函数替换为代理函数
rename_function('strtoupper', 'original_strtoupper');
override_function('strtoupper', '$str', 'return my_strtoupper($str);');
在实现协程客户端时,Hook 可以用来实现非阻塞式的网络 IO 操作,从而提高程序的并发处理能力。具体来说,可以使用 Hook 技术截获 PHP 内置的 socket 相关函数,如
socket_connect()、socket_recv()等,将其封装成可 yield 的协程函数,并利用 PHP 的 Generator 特性实现协程调度。
最后附上Event Loop官方解释
Event Loop(事件循环)是一种用于处理事件的机制,通常被用于实现异步编程模型。它是一种循环结构,不断地监听事件的发生,然后根据事件的类型和状态来触发相应的回调函数。
在异步编程模型中,Event Loop 被用于协调多个协程之间的执行,它负责管理协程的状态、调度和切换,从而实现非阻塞的并发执行。当一个协程需要等待 I/O 操作或者其他阻塞操作完成时,它会被切换出去,让其他可执行的协程继续执行,从而提高程序的并发能力和效率。
注意:
如果一个协程一直被阻塞,那么它就无法继续执行下去,同时也不能切换出去运行其他协程。
由于 Event Loop 是单线程的,只有等到阻塞的 I/O 操作完成后,才会将阻塞的协程重新添加到可执行队列中,等待继续执行。如果阻塞的时间很长,那么其他协程就无法得到执行,整个程序的效率就会降低。
因此,在编写协程时,需要注意避免阻塞操作,尽可能地使用异步 I/O 和非阻塞操作,从而避免阻塞操作对程序性能的影响,提高程序的并发能力和效率。