当前位置: 首页 > 后端技术 > PHP

Swoole4.x的协程变量访问安全和协程连接池实现

时间:2023-03-29 18:16:38 PHP

访问安全问题为什么说有访问安全问题呢?传统上,在php环境中,很少有Phper会遇到所谓的变量安全访问问题。例如,代码大概如下:classdb{protectedstatic$instance;受保护的$dbCon;function__construct(){/**这里我们使用stdclass来模拟一个数据库连接*/$this->dbCon=new\stdClass();}publicstaticfunctiongetInstance(){if(!isset(self::$instance)){self::$instance=newdb();}返回自我::$实例;}functiondbCon(){return$this->dbCon;}}$con=db::getInstance()->dbCon();$con->key='new';var_dump($con->key);这是fpm模式下很常见的数据库连接单例模式的使用。乍一看没什么问题,但实际上在协程环境下,会出现跨协程连接的问题。例如,go(function(){go(function(){db::getInstance()->dbCon()->key='one';//假设这条sql执行了1s\co::sleep(1);var_dump(db::getInstance()->dbCon()->key);});go(function(){db::getInstance()->dbCon()->key='two';//假设这样sql执行0.1s\co::sleep(0.1);var_dump(db::getInstance()->dbCon()->key);});});我们会发现,在上面的代码中,协程2的数据污染了协程1的数据,所以这是肯定不能接受的。上下文管理器为了解决这个问题,我们引入了协程上下文管理的概念,从而实现各个协程环境中的数据隔离。类dbContext{private$container=[];私有静态$实例;publicstaticfunctiongetInstance(){if(!isset(self::$instance)){self::$instance=newdbContext();}返回自我::$实例;}函数dbCon(){$cid=\co::getCid();if(!isset($this->container[$cid])){$this->container[$cid]=newstdClass();推迟(函数(){$this->destroy();});}返回$this->container[$cid];}functiondestroy(){$cid=\co::getCid();if(!isset($this->container[$cid])){unset($this->container[$cid]);}}}go(function(){go(function(){dbContext::getInstance()->dbCon()->key='one';//假设这个sql执行了1s\co::sleep(1);var_dump(dbContext::getInstance()->dbCon()->key);});go(function(){dbContext::getInstance()->dbCon()->key='two';//假设这条sql执行了0.1s\co::sleep(0.1);var_dump(dbContext::getInstance()->dbCon()->key);});});在上面的代码中,我们使用各个协程的id作为各个协程栈的数据token,使用defer方法实现了各个协程退出时的数据自动清理,从而避免了连接池和连接池不难发现通用版内存泄漏的协程上下文管理,在上面的代码中,其实还是一种短连接的管理方式,没有办法复用链接,因为本文只是为了解释基本原理,对于有兴趣的可以查看Easyswoole框架的连接池和协程上下文管理器。项目主页位于www.easyswoole.com。如果喜欢和帮助,可以在github仓库给easyswoole点个赞。

最新推荐
猜你喜欢