我们在首次使用 Swoole 框架时候发现有三类变量问题需要主要,问题的主要造成因素应该是 Swoole 常驻内容变量内存共享导致的主要有一下三类

  • 使用 global 关键词声明的变量
  • 使用 static 关键词声明的类静态变量、函数静态变量
  • PHP的超全局变量,包括$_GET,$_POST,$GLOBALS等

 这三种类型的变量在 Swoole 模式下都存在并发安全问题

Swoole 变量问题

ktf6x9mu.png

 A,B,C三人依次访问设置变量分别为1,2,3程序返回时分别对A,B,C三人的请求进行延迟3,2,1秒按照正常逻辑来看A,B,C三人访问设置的1,2,3那么对应返回的值就是设置的值,但是通过使用swoole发现三人返回的结果为最后一个人设置的值也就是3这种情况就是我们刚才所说的三类变量问题

Swoole 全局变量 Global 问题演示

    // 数据混乱演示
   public function index()
   {
       // 并发安全问题,会出现数据混乱
       // 第一次访问 http://192.168.100.103:8088/Context/index?i=1
       // 第二次访问 http://192.168.100.103:8088/Context/index?i=2
       // 返回返回查看第一次访问返回的结果不是预期的1,而是2,所以说这种全局变量保存上下文资源存在并发安全问题
       global $aaa;
       $aaa = $this->request->param('i');
       if ($this->request->param('i') == 1) {
           Coroutine::sleep(3);
       }
       $this->test1();
       return $aaa;
   }

   protected function test1()
   {
       global $aaa;
       dump($aaa);
   }

Swoole 静态变量 Static 问题演示

class StaticAaa extends BaseController
{

    protected static $i;

    // 数据混乱演示
    public function index()
    {
        // 并发安全问题,会出现数据混乱
        // 第一次访问 http://192.168.100.103:8088/StaticAaa/index?i=1
        // 第二次访问 http://192.168.100.103:8088/StaticAaa/index?i=2
        // 返回返回查看第一次访问返回的结果不是预期的1,而是2,所以说这种全局变量保存上下文资源存在并发安全问题

        self::$i = $this->request->param('i');
        if ($this->request->param('i') == 1) {
            Coroutine::sleep(2);
        }
        return self::$i;
    }

}

Swoole 超级全局变量 $_GET 问题演示

    // 数据混乱演示
    public function index()
    {
        // 并发安全问题,会出现数据混乱
        // 第一次访问 http://192.168.100.103:8088/StaticAaa/index?i=1
        // 第二次访问 http://192.168.100.103:8088/StaticAaa/index?i=2
        // 返回返回查看第一次访问返回的结果不是预期的1,而是2,所以说这种全局变量保存上下文资源存在并发安全问题

        $_GET['i'] = $this->request->param('i');
        if ($this->request->param('i') == 1) {
            Coroutine::sleep(2);
        }
        return $_GET['i'];
    }

Swoole 三类变量问题解决方案

 通过阅读文档发现 swoole 已经给出了解决的方法,我们只需要使用swoole 上下文 Context 类保存上下文临时数据即可。
文档地址

  // 正确实例
  public function index()
  {
      // 第一次访问 http://192.168.100.103:8088/Ok/index?i=1
      // 第二次访问 http://192.168.100.103:8088/Ok/index?i=2
      $contextKey = 'aaa';
      $i = $this->request->param('i');
      \think\swoole\coroutine\Context::setData($contextKey, $i);
      if ($this->request->param('i') == 1) {
          Coroutine::sleep(2);
      }
      return \think\swoole\coroutine\Context::getData($contextKey);
  }

关于php使用 swoole 框架静态变量,全局变量并发安全问题已经解决了