Skip to content

Latest commit

 

History

History
101 lines (76 loc) · 3.09 KB

v6.md

File metadata and controls

101 lines (76 loc) · 3.09 KB

6.0

目标

引入多线程运行模式,使 Swoole 实现多线程+协程的运行方式。

背景

Swoole 服务器编程开发中,协程的出现已经解决了大部分难题,但是我们发现跨进程读写数据依然很难,需要借助 进程间通信、Redis、Swoole\Table 或其他共享内存实现。

RedisIPC 进程间通信方式性能较差。而 Swoole\Table 的问题是需要固定分配内存,无法扩容,存在诸多限制。

除此之外,多进程的调试非常麻烦,例如我们要使用 gdb 就需要 gdb -p 逐个进程去追踪,而 Java 、Golang 这样的多线程模型,只有一个进程,调试更简单。实现一些底层的工具也会更容易。

实现方式

修改 swoole-cliCLI SAPI 加入参数开启多线程,仅在 ZTS 模式下可用。

进程初始化时,按照传入的参数创建多个 TSRM 管理资源。

tsrm_startup(128, 1, 0, NULL);

创建新线程时,隔离全局变量

std::thread newThread1([=]() {
    ts_resource(1);
    zend_first_try {
        mt_debug("thread-1");
        do_cli(argc, argv);
    }
    zend_end_try();
});

运行结果

# index.php
<?php
echo "hello world\n";
sleep(10);
echo "end\n";
swoole-cli --threads=8 index.php
[thread-0]	TheadId=140327446116480, mainThread=1, CG(compiled_filename)=(nil)
[thread-1]	TheadId=140327442708032, mainThread=0, CG(compiled_filename)=(nil)
hello world
[thread-2]	TheadId=140327434315328, mainThread=0, CG(compiled_filename)=(nil)
hello world

使用 ps aux 可以看到只有一个进程:

ps aux|grep swoole-cli
htf       783550  0.2  0.0 171424 12028 pts/11   Sl+  10:51   0:00 swoole-cli --threads=8 index.php

Swoole 适配

  • 去掉进程管理器,运行方式与 SWOOLE_BASE 基本相同,每个线程一个 EventLoop 和协程调度器
  • 隔离 WorkerG 全局变量,使 Worker 作为线程独立运行
  • new Server 时需要加锁,避免重复创建
  • Server::start() 进入事件循环,监听 Worker 进程事件

缺点

  • 发生 Fatal ErrorCrash 整个进程都会退出
  • ZTS 和 锁的操作可能会额外的开销
  • 不支持 thread-context

新的 API

<?php
use Swoole\Thread;

# 防止并发
Thread::once(function () {
    echo "hello world";
});

# 获取线程 ID
echo Thread::id();

# 相当于 C++ 的 std::unorderedmap<long, std::string>
$map1 = Thread::map('global_map_1', Thread::TYPE_INT, Thread::TYPE_STRING); 

# 相当于 C++ 的 std::unorderedmap<std::string, double>
$map2 = Thread::map('global_map_2', Thread::TYPE_STRING, Thread::TYPE_FLOAT);

# 相当于 C++ 的 std::vector<long>
$list = Thread::list('global_list_1', Thread::TYPE_INT);
  • Thread::once() 可以让一个函数只运行一次
  • Thread::map() 创建全局 HashTableThread::list() 创建全局列表,底层会自动加锁,是线程安全的
  • 支持 int64/double/string 3 种格式

其他更新

  • 移除 Coroutine\MySQLCoroutine\RedisCoroutine\PostgreSQL ,已被 pdo_mysql/mysqliext-redispdo_pgsql 替代