Swoole 一键协程化设置 flags 的问题

简介: 从 Swoole4 版本开始,提供了一键协程化的功能,采用 Hook 原生 PHP 函数的方式实现协程客户端,通过一行代码就可以让原来的同步 IO 的代码变成可以协程调度的异步 IO,即一键协程化。

从 Swoole4 版本开始,提供了一键协程化的功能,采用 Hook 原生 PHP 函数的方式实现协程客户端,通过一行代码就可以让原来的同步 IO 的代码变成可以协程调度的异步 IO,即一键协程化。

目前有两种方式设置要 Hook 的函数范围:

Swoole\Coroutine::set(['hook_flags'=> SWOOLE_HOOK_ALL]);

Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);

同时从v4.6.0版本开始,协程容器中默认开启所有 Hook,即 SWOOLE_HOOK_ALL

use Swoole\Runtime;
use function Swoole\Coroutine\run;

run(function () {
    assert(Runtime::getHookFlags() === SWOOLE_HOOK_ALL);
});

那么有两种方式可以设置,具体使用哪种方式来设置呢?

先来看一段代码:

基于 Swoole v4.7.1 版本,并开启了 --enable-swoole-curl
use Swoole\Coroutine;
use Swoole\Runtime;

function hook_dump()
{
    var_dump([
        'file' => (Runtime::getHookFlags() & SWOOLE_HOOK_FILE) === SWOOLE_HOOK_FILE,
        'native' => (Runtime::getHookFlags() & SWOOLE_HOOK_NATIVE_CURL) === SWOOLE_HOOK_NATIVE_CURL,
        'curl' => (Runtime::getHookFlags() & SWOOLE_HOOK_CURL) === SWOOLE_HOOK_NATIVE_CURL,
    ]);
}

Coroutine\run(function () {
    hook_dump();

    $flags = SWOOLE_HOOK_ALL ^ (SWOOLE_HOOK_FILE | SWOOLE_HOOK_NATIVE_CURL | SWOOLE_HOOK_CURL);

    Coroutine::set(['hook_flags' => $flags]);
    hook_dump();

    Runtime::enableCoroutine($flags);
    hook_dump();
});

是不是觉得应该输出为:

array(3) {
  ["file"]=>
  bool(true)
  ["native"]=>
  bool(true)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}

但实际上输出结果却为:

array(3) {
  ["file"]=>
  bool(true)
  ["native"]=>
  bool(true)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(true)
  ["native"]=>
  bool(true)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}

这个时候就会以为是Coroutine::set(['hook_flags' => $flags]);没生效,是 Bug 吗? 当然不是 Bug 了。

分开来测试一下:

use Swoole\Coroutine;
use Swoole\Runtime;

function hook_dump()
{
    var_dump([
        'file' => (Runtime::getHookFlags() & SWOOLE_HOOK_FILE) === SWOOLE_HOOK_FILE,
        'native' => (Runtime::getHookFlags() & SWOOLE_HOOK_NATIVE_CURL) === SWOOLE_HOOK_NATIVE_CURL,
        'curl' => (Runtime::getHookFlags() & SWOOLE_HOOK_CURL) === SWOOLE_HOOK_NATIVE_CURL,
    ]);
}

$flags = SWOOLE_HOOK_ALL ^ (SWOOLE_HOOK_FILE | SWOOLE_HOOK_NATIVE_CURL | SWOOLE_HOOK_CURL);
Coroutine::set(['hook_flags' => $flags]);
Coroutine\run(function () {
    hook_dump();

    Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]);
    hook_dump();
});

再增加一个协程嵌套进行测试

Coroutine\run(function () {
    hook_dump();

    Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]);
    go(function () {
        hook_dump();
    });
});

输出发现全是false,也就是说在协程中通过Coroutine::set动态设置 flags 不会生效

array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}

将协程容器中的Coroutine::set换为Runtime::enableCoroutine进行测试

Coroutine\run(function () {
    hook_dump();

    Runtime::enableCoroutine(SWOOLE_HOOK_ALL);

    hook_dump();

    go(function () {
        hook_dump();
    });
});

发现结果是生效的。

array(3) {
  ["file"]=>
  bool(false)
  ["native"]=>
  bool(false)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(true)
  ["native"]=>
  bool(true)
  ["curl"]=>
  bool(false)
}
array(3) {
  ["file"]=>
  bool(true)
  ["native"]=>
  bool(true)
  ["curl"]=>
  bool(false)
}

综上所述,可以得到以下结论:

  1. Runtime::enableCoroutine() 可以在服务启动后 (运行时) 动态设置 flags,调用方法后当前进程内全局生效
  2. Coroutine::set() 可以理解为 PHP 的 ini_set(),需要在 Server->start() 前或 Coroutine\run() 前调用,否则设置的 hook_flags 不会生效
  3. 无论是 Coroutine::set() 还是 Runtime::enableCoroutine() 的方式,都应该只调用一次,重复调用会被覆盖

Runtime::enableCoroutine()支持动态设置 flags,而Coroutine::set()的方式不支持。

目录
相关文章
|
安全 API 网络安全
Swoole v4.6.0 版本发布,支持原生 curl 协程客户端
Swoole v4.6.0 版本发布了,同样也是 2021 年的首个版本更新。 作为一个 y 版本发布,此次更新也包含了不兼容的修改以及许多的新功能
727 0
|
5月前
|
PHP 调度 容器
Swoole 源码分析之 Coroutine 协程模块
协程又称轻量级线程,但与线程不同的是;协程是用户级线程,不需要操作系统参与。由用户显式控制,可以在需要的时候挂起、或恢复执行。
78 1
Swoole 源码分析之 Coroutine 协程模块
|
网络协议 关系型数据库 MySQL
swoole协程框架?
Swoole是一个高性能的PHP扩展,可以用于构建异步、并发和高性能的网络应用。它提供了许多底层网络通信和多进程管理的功能,使得开发者可以更轻松地编写高性能的服务器程序。
96 0
|
关系型数据库 MySQL 大数据
利用原生swoole协程批量向数据库插入1000W条数据
一直再听说高并发,没有体验过真正的高并发,这次体验下1000w数据表(不知道算不算大数据),刚好体验下mysql索引的性能;
197 0
|
Go
「让我们一起Golang」怎样出让协程资源和设置可用CPU核心数
「让我们一起Golang」怎样出让协程资源和设置可用CPU核心数
600 0
|
PHP C++
以swoole为例,学习如何实现协程
# 聊聊Swoole2.0协程 Swoole 2.0正式版发布了。2.0版本最大的更新是增加了对协程(Coroutine)的支持。正式版已同时支持PHP5和PHP7。基于Swoole2.0协程PHP开发者可以已同步的方式编写代码,底层自动进行协程调度,转变为异步IO。解决了传统异步编程嵌套回调的问题。 目前Swoole底层内置的协程客户端组件包括:udpclient、tcpclient、h
3989 0
|
NoSQL Go PHP
Swoole 4.1.0 正式版发布,支持原生 Redis/PDO/MySQLi 协程化
重大新特性 支持 Redis/PDO/MySQLi 从4.1.0版本开始支持了对PHP原生Redis、PDO、MySQLi协程化的支持。
1212 0
|
5月前
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
51 1
使用python实现一个用户态协程
|
2月前
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
20 0
|
4月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
83 10