workerman知识清单

 

Worker类:静态Worker统一管理实例worker

$this->workerId                    = \spl_object_hash($this);
static::$_workers[$this->workerId] = $this;
static::$_pidMap[$this->workerId]  = array();

 

进程端口复用原理

参考:https://www.jianshu.com/p/97cc8c52d47a

惊群效应

为了提升性能,一般的服务端程序在运行时都有多个进程(俗称 Worker)监听同一个 Socket,在没有客户端连接到来的时候,这些Worker是处于挂起状态的,不消耗CPU资源。

只有一个 Worker 可以获得处理这个连接的机会,其他Worker在竞争失败后继续回到挂起状态。唤醒 Worker 的过程是要消耗CPU资源的,Worker 数量越多,消耗的 CPU 资源就越多,造成了资源的浪费。这就是常说的 惊群效应

代码细节

#Worker 类是 Workerman 里最主要的类,其中有个 listen() 函数
protected
function listen() { ... if (!$this->_mainSocket) { ... $this->_mainSocket = stream_socket_server(...); ... } ... }
#当 reusePort 为 false 时,主进程在创建 Worker 之前就调用了 listen() 函数
protected function initWorkers() { .... if (!$worker->reusePort) { $worker->listen(); } .... }
#当 reusePort 为 true 时,情况就不同了。主进程在创建 Worker 前不会调用 listen(),而是在创建完 Worker 后由每个 Worker 自行发起 listen() 调用
protected static function forkOneWorkerForLinux($worker) { ... $pid = pcntl_fork(); if ($pid === 0) { if ($worker->reusePort) { $worker->listen(); } ... } ... }
#想要内核开启 reuseport 功能,需要手动设置 Socket 的 context
if ($this->reusePort) { $context = stream_context_create(); stream_context_set_option($context, 'socket', 'so_reuseport', 1); }

定时器

1,定时器是用来实现定时任务的,分为持续间隔计时(类似setTimeInterval())和一次性计时(类似setTimeOut())

2,定时器实现有两种方式:使用事件和任务数组

//初始化
Timer::init(static::$globalEvent); if ($event) { self::$_event = $event; return; } if (\function_exists('pcntl_signal')) { \pcntl_signal(\SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); }
//添加定时任务 Timer
::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($one_worker_pid, \SIGKILL), false); if (self::$_event) { return self::$_event->add($time_interval, $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); } if (!\is_callable($func)) { Worker::safeEcho(new Exception("not callable")); return false; } if (empty(self::$_tasks)) { \pcntl_alarm(1); } $run_time = \time() + $time_interval; if (!isset(self::$_tasks[$run_time])) { self::$_tasks[$run_time] = array(); } self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId; self::$_status[self::$_timerId] = true; self::$_tasks[$run_time][self::$_timerId] = array($func, (array)$args, $persistent, $time_interval);
//执行任务 Timer
::tick() if (self::$_event) { return self::$_event->add($time_interval, $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); } $time_now = \time(); foreach (self::$_tasks as $run_time => $task_data) { if ($time_now >= $run_time) { foreach ($task_data as $index => $one_task) { $task_func = $one_task[0]; $task_args = $one_task[1]; $persistent = $one_task[2]; $time_interval = $one_task[3]; try { \call_user_func_array($task_func, $task_args); } catch (\Exception $e) { Worker::safeEcho($e); } if($persistent && !empty(self::$_status[$index])) { $new_run_time = \time() + $time_interval; if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = array(); self::$_tasks[$new_run_time][$index] = array($task_func, (array)$task_args, $persistent, $time_interval); } } unset(self::$_tasks[$run_time]); } }

事件

有3种事件:

1,信号事件:

$this->_eventSignal

2,socket io事件

$this->_allEvents

3,定时器事件

$this->_eventTimer
//绑定事件
if ($this->transport !== 'udp') {
      static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptConnection'));
} else {
      static::$globalEvent->add($this->_mainSocket, EventInterface::EV_READ, array($this, 'acceptUdpConnection'));
}
// reinstall stop signal handler
static::$globalEvent->add(\SIGINT, EventInterface::EV_SIGNAL, $signalHandler);
// reinstall graceful stop signal handler
static::$globalEvent->add(\SIGHUP, EventInterface::EV_SIGNAL, $signalHandler);
// reinstall reload signal handler
static::$globalEvent->add(\SIGUSR1, EventInterface::EV_SIGNAL, $signalHandler);
// reinstall graceful reload signal handler
static::$globalEvent->add(\SIGQUIT, EventInterface::EV_SIGNAL, $signalHandler);
// reinstall status signal handler
static::$globalEvent->add(\SIGUSR2, EventInterface::EV_SIGNAL, $signalHandler);
// reinstall connection status signal handler
static::$globalEvent->add(\SIGIO, EventInterface::EV_SIGNAL, $signalHandler);

//事件轮询
static::$globalEvent->loop();//系统自动触发

//解绑事件
static::$globalEvent->del($this->_mainSocket, EventInterface::EV_READ);

//销毁所有事件
static::$globalEvent->destroy();
//统计事件
static::$globalEvent->getTimerCount();

//定时器事件方法
\Workerman\Timer::$_event->clearAllTimer();
static::$globalEvent->getTimerCount()

 

 

 

 

 

 

 

posted @ 2021-06-29 10:10  小匡程序员  阅读(118)  评论(0编辑  收藏  举报