商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Swoole中Event::add与Event::set的区别

Swoole中Event::add与Event::set的区别

  发布于2026-07-07 阅读(0)

扫一扫,手机访问

先看两个很容易搞混的函数:swoole_event_addswoole_event_set。它们都是用来向Swoole事件循环注册或调整文件描述符(fd)监听行为的,语义上完全不同——如果混着用,很可能碰到回调不执行、事件丢失,甚至就给你返回一个false,你都不知道是怎么回事。

Swoole中Event::add与Event::set的区别

那么,要怎么区分它们?

必须先swoole_event_add,才能调swoole_event_set

很多人容易犯一个错:认为swoole_event_set也可以独立注册一个fd。实际上它只对已经在Reactor里存在的fd有作用。换句话说,这个fd要是从来没有swoole_event_add进去过,set就直接返回false,而且没有任何异常提示。这一点最坑。

  • 一个常见的错误场景:写了一段swoole_event_set($fd, $cb, null, SWOOLE_EVENT_READ),结果返回了false,还以为是参数填错了,其实是忘了先add
  • 如果你用的是Swoole v4.8及以上,可以在调用前用swoole_event_exist($fd)检查一下。如果是v4.7或更早的版本,那就只能靠自己维护一个fd状态映射表了。
  • 还有一点要注意:即使你是用fopen或者stream_socket_client创建的资源,也必须显式地swoole_event_add,它才会真正进入事件循环的流程。

swoole_event_add是初始化,swoole_event_set是动态调整

从实际运行表现来看,swoole_event_add干的是三件事:把fd注册进epoll或kqueue、设置初始回调、启用指定事件掩码。而swoole_event_set只处理两件事:替换回调函数(前提是传了非null的值),以及开关事件监听(靠$flags参数控制)。

  • 关键的不同在于:swoole_event_add中的$write_callback$event_flag是必填逻辑的一部分;而swoole_event_set里如果对应参数传了null,意思是不修改,而不是清空。
  • 举个典型场景:MySQL异步查询做完后,先通过swoole_event_add监听可读状态,等reap_async_query结束了,再用swoole_event_set($fd, null, null, SWOOLE_EVENT_WRITE)把监听模式切到可写,为下一次查询做准备。
  • 有一个很容易踩的坑:swoole_event_set($fd, null, null, SWOOLE_EVENT_READ)并不会清除原有的回调,它只是把可写关了、把可读打开了——之前的read_callback依然有效。

回调函数不会被swoole_event_set释放

不管你给$read_callback$write_callback传多少次null,只要没用swoole_event_del,PHP层回调的zval就会一直被引用着,内存不会释放。闭包捕获的那些变量也会一直活着。

  • 所以,在长连接场景里,如果反复用swoole_event_set替换回调但不del,内存会一点一点涨上去,时间长了很可能是问题。
  • 正确做法是:当你确定不再需要监听这个fd时,一定要调用swoole_event_del($fd)来配对清理。
  • 值得说明的是:swoole_event_del会把读/写回调一次全释放,同时把fd从Reactor里移除,不会管你之前调了多少次set

最后,最容易忽略的一点:事件掩码($flags)和回调函数是解耦的。你可以只改掩码不改回调,也可以只改回调不改掩码。但是,一旦掩码里没有SWOOLE_EVENT_READ,却设了$read_callback,这个回调永远不会被执行——Swoole底层只按掩码投递事件,不会校验回调是否存在。

本文转载于:https://www.php.cn/faq/2778531.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注