SwooleTable 是基于共享内存的哈希表,Map 只是 PHP 关联数组;Table 必须主进程创建、显式定义字段、用 ASCII 字符串作 key,不支持嵌套和 NULL,size 指桶数量而非行数。

Table 和 Map 在 Swoole 里根本不是一回事
很多人一看到 SwooleTable 和 Map(比如 swoole_server->addProcess 里传的 Map 参数)就默认它们是同类数据结构,其实完全不是。前者是 Swoole 提供的、基于共享内存的高性能哈希表实现,后者只是 PHP 层面一个普通关联数组(array),在底层压根不参与共享内存管理。
常见错误现象:Table 写入后子进程读不到,或反复 new Table 导致内存泄漏——本质是混淆了「跨进程可见」和「PHP 变量传递」的边界。
-
SwooleTable必须在主进程创建,且所有子进程(worker/task 进程)通过同一块共享内存地址访问,它不依赖 PHP 引用计数 -
Map类型参数(如onConnect回调里的$client_info)只是函数调用时传入的临时数组,生命周期仅限当前回调执行期 - 不能把
Table实例存进$_SERVER或全局变量再期望在其他进程里用——那只是 PHP 层对象引用,底层共享内存指针不会自动同步
Table 初始化必须指定 size,且 size 不是容量而是桶数量
SwooleTable 的 size 参数常被误认为“最多存多少行”,实际它是哈希桶(bucket)的数量,直接影响冲突链长度和查找性能。设得太小会导致大量哈希碰撞,查询退化为链表遍历;设得太大则浪费共享内存。
使用场景:如果你预期存 10 万条连接信息,size 建议设为 131072(2^17)或更高,而非刚好 100000。
- 初始化时必须显式调用
$table->column()定义字段类型,未定义的字段无法写入(会静默失败,无报错) -
string类型字段必须指定长度,例如$table->column('uid', Table::TYPE_STRING, 64),超长截断不报错 - 整型字段(
TYPE_INT/TYPE_FLOAT)不支持 NULL,写入 null 会被转成 0 或 0.0
Table 的 key 是字符串,但底层用的是 MurmurHash3,不支持中文或特殊字符直接作 key
虽然你可以用 $table->set('用户123', [...]),但 Swoole 底层对 key 做了 MurmurHash3 计算,若 key 含 UTF-8 多字节字符(如中文)、控制字符或 ,哈希结果可能不稳定,导致 set 成功但 get 找不到。
常见错误现象:本地测试用英文 key 正常,上线后用手机号/UUID 拼接中文昵称作 key,部分数据查不到。
- 安全做法是统一用 ASCII 字符串做 key:如
md5($uid)、sprintf('%010d', $uid)、或 base64_encode(urlencode($str)) - 避免用
json_encode($arr)结果作 key——序列化结果含空格、引号等,易触发哈希异常 - key 长度建议控制在 64 字节内,过长会增加哈希计算开销,也挤占 bucket 空间
Table 不支持嵌套结构,数组字段只是“扁平化存储”
SwooleTable 所有字段都是基础类型(int/float/string),所谓“数组字段”只是你把 JSON 字符串写进 string 列,然后自己 json_decode。它本身没有对象模型、没有嵌套、没有动态 schema。
性能影响:频繁 json_encode/json_decode 会吃 CPU,尤其在高并发短连接场景下,比直接存多个 string/int 字段慢 3–5 倍。
- 如果字段逻辑固定(如
ip、port、login_time),务必拆成独立列,用原生类型存 - 需要存变长列表(如用户权限数组)时,可考虑用逗号分隔字符串 +
explode(),或改用 Redis 等外部存储 -
Table::TYPE_STRING字段最大长度受限于初始化时设定值,超出部分被截断,且不会抛异常
真正难处理的不是语法或 API,而是共享内存的“无状态性”——它不帮你做类型校验、不维护引用关系、不感知 PHP 生命周期。一旦忘了 key 编码规则,或误把 Table 当普通数组 clone,问题就会藏在高并发下的偶发丢失里。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/41189.html