应使用swoole\coroutine::stats()['elapsed_time']获取协程真实cpu耗时,该值仅统计协程实际执行时间,不含i/o等待等挂起时段;需配合协程id隔离多任务统计,并避免使用microtime()或sleep()类wall time方法。

要准确测量Workerman协程内某段逻辑的真实耗时,不能依赖常规的microtime()差值——因为协程可能被调度器挂起,期间CPU时间不归你用,但wall time仍在走。直接减毫秒数会把挂起等待时间也计入,导致统计严重失真。
用Swoole\Coroutine::stats()获取当前协程生命周期信息
在协程起始处调用Swoole\Coroutine::stats(),它返回一个关联数组,其中elapsed_time字段记录的是该协程自创建以来实际占用CPU的时间(单位:微秒),不含调度空转、I/O等待等挂起时段。
这一步操作起来很简单,直接在协程开头写一行:$start = Swoole\Coroutine::stats()['elapsed_time'];
【必须在协程内部调用,且只能在当前协程上下文中获取自身数据】。若在非协程环境或跨协程读取,返回值为false或0,统计彻底失效。
配合协程ID做多任务隔离统计
当多个协程并发运行,需区分各自耗时,仅靠elapsed_time不够——它只反映单个协程累计CPU时间,无法定位某次调用片段。
方法一:手动打点+协程ID绑定
第一步:用Swoole\Coroutine::id()获取当前协程唯一ID
第二步:将起始elapsed_time存入全局数组$coroTimers[$cid] = $start;
第三步:结束时再次调用Swoole\Coroutine::stats(),用当前elapsed_time减去存储的起始值,结果即为本次执行段真实CPU耗时
方法二:封装成函数一次性提取
定义函数function coro_timer_start() { return [Swoole\Coroutine::id(), Swoole\Coroutine::stats()['elapsed_time']]; }
再定义function coro_timer_end($start) { [$cid, $begin] = $start; $now = Swoole\Coroutine::stats()['elapsed_time']; return $now - $begin; }
调用方式:$timer = coro_timer_start(); ... 业务逻辑 ... echo coro_timer_end($timer);
规避常见陷阱:别用sleep()测协程时间
在协程里写swoole_timer_after(1000, function () { ... });后立刻用microtime()比对,得到的差值≈1000ms——但这不是协程执行时间,是Wall Clock流逝时间。协程在这1秒里全程挂起,CPU时间为0。
真正要统计的是协程被调度执行的那几毫秒,比如解析JSON、拼接字符串、计算哈希这些纯CPU操作。只要中间夹了co::sleep()、mysql->query()、http_client->get()这类I/O操作,它们的等待时间必须从统计中剔除。
这正是Swoole\Coroutine::stats()['elapsed_time']存在的根本价值:它只计量CPU真正在干活的时间。











