• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
孙龙 程序员
少时总觉为人易,华年方知立业难
博客园    首页    新随笔    联系   管理    订阅  订阅
Event IO Process

 先了解一下process和event loop

EventLoop

除了异步Server和Client库之外,Swoole扩展还提供了直接操作底层epoll/kqueue事件循环的接口。可将其他扩展创建的socket,PHP代码中stream/socket扩展创建的socket等加入到Swoole的EventLoop中。

事件优先级

  1. 通过Process::signal设置的信号处理回调函数
  2. 通过Event::defer设置的延迟执行函数
  3. 通过Timer::tick和Timer::after设置的定时器回调函数
  4. 通过Event::cycle设置的周期回调函数

swoole_event_add函数用于将一个socket加入到底层的reactor事件监听中。此函数可以用在Server或Client模式下

参数

参数1可以为以下四种类型:

  • int,就是文件描述符,包括swoole_client->$sock、swoole_process->$pipe或者其他fd
  • stream资源,就是stream_socket_client/fsockopen创建的资源
  • sockets资源,就是sockets扩展中socket_create创建的资源,需要在编译时加入 ./configure --enable-sockets
  • object,swoole_process或swoole_client,底层自动转换为管道或客户端连接的socket

参数2为可读回调函数,参数3为可写事件回调,可以是字符串函数名、对象+方法、类静态方法或匿名函数,当此socket可读时回调指定的函数。

参数4为事件类型的掩码,可选择关闭/开启可读可写事件,如SWOOLE_EVENT_READ,SWOOLE_EVENT_WRITE,或者SWOOLE_EVENT_READ | SWOOLE_EVENT_WRITE

在 Server 程序中使用时,必须在 Worker 进程启动后使用。在 Server::start 之前不得调用任何异步 IO 接口

 

在fpm当中一个请求结束了线程就被关掉了,注册的事件就不会再去监听了

event lop实例:

命令符聊天室

主要应用点:

异步读取来自副武器的数据

异步读取来自终端的输入

手动退出聊天室

 

监听服务器的读和写操作 

服务端是不会挺停止的

process

PHP自带的pcntl,存在很多不足,如

  • pcntl没有提供进程间通信的功能
  • pcntl不支持重定向标准输入和输出
  • pcntl只提供了fork这样原始的接口,容易使用错误
  • swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。

swoole_process提供了如下特性:

  • swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
  • swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据
  • 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
  • swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信

curl实例:多进程执行任务和执行一个外部的程序

<?php
/**
 * Created by PhpStorm.
 * User: baidu
 * Date: 18/3/17
 * Time: 上午12:31
 */

echo "process-start-time:".date("Ymd H:i:s");
$workers = [];
$urls = [
    'http://baidu.com',
    'http://sina.com.cn',
    'http://qq.com',
    'http://baidu.com?search=singwa',
    'http://baidu.com?search=singwa2',
    'http://baidu.com?search=imooc',
];

for($i = 0; $i < 6; $i++) {
    // 子进程
    $process = new swoole_process(function(swoole_process $worker) use($i, $urls) {
        // curl
        $content = curlData($urls[$i]);
        //echo $content.PHP_EOL;
        $worker->write($content.PHP_EOL);
    }, true);
    $pid = $process->start();
    $workers[$pid] = $process;
}

foreach($workers as $process) {
    echo $process->read();
}
/**
 * 模拟请求URL的内容  1s
 * @param $url
 * @return string
 */
function curlData($url) {
    // curl file_get_contents
    sleep(1);
    return $url . "success".PHP_EOL;
}
echo "process-end-time:".date("Ymd H:i:s");
$process = new swoole_process(function(swoole_process $pro) {
    // todo
    // php redis.php
    $pro->exec("/home/work/study/soft/php/bin/php", [__DIR__.'/../server/http_server.php']);
}, false);

$pid = $process->start();
echo $pid . PHP_EOL;

swoole_process::wait();

 process实例:

<?php
class BaseProcess{
    private $process;
    public function __construct()
    {
        $this->process = new swoole_process([$this,'run'],false,true);
        $this->process->start();
        swoole_event_add($this->process->pipe,function($pipe){
            $data = $this->process->read();
            echo 'RECV: '.$data.PHP_EOL;
        });
    }

    public function run($worker){
        swoole_timer_tick(1000,function($timer_id){
            static $index = 0 ;
            $index += 1;
            $this->process->write('hello sunlong');
            var_dump($index);
            if($index == 10){
                swoole_timer_clear($timer_id);
            }
        });
    }
}

new BaseProcess();
swoole_process::signal(SIGCHLD,function($sig){
    while($ret = swoole_process::wait(false)){
        echo "PID={$ret['pid']}\n";
    }
});

返回结果

[root@localhost php]# php7 process2.php 
int(1)
RECV: hello sunlong
int(2)
RECV: hello sunlong
int(3)
RECV: hello sunlong
int(4)
RECV: hello sunlong
int(5)
RECV: hello sunlong
int(6)
RECV: hello sunlong
int(7)
RECV: hello sunlong
int(8)
RECV: hello sunlong
int(9)
RECV: hello sunlong
int(10)
RECV: hello sunlong
PID=2903

 

上述案例  创建子进程,然后执行定时器,定时器向管道写入数据;swoole_event_add监听管道写事件回调(异步监听管道数据),读取到写的内容并输出。

此时程序还没终止,event loop还在监听管道数据

 

 下面是消息队列作为进程间通信  消息队列同步的 不支持异步

 

[root@localhost php]# php7 process2.php 
int(1)
RECV: hello sunlong
int(2)
RECV: hello sunlong
int(3)
RECV: hello sunlong
int(4)
RECV: hello sunlong
int(5)
RECV: hello sunlong
int(6)
RECV: hello sunlong
int(7)
RECV: hello sunlong
int(8)
RECV: hello sunlong
int(9)
RECV: hello sunlong
int(10)
RECV: hello sunlong

  

升华一下  实现简单的进程池 动态扩展进程池 同时处理更多任务

但是推荐使用swoole_server+task做任务池 

swoole_process->exec

process在swoole_server中还是有实际运用的,比如执行脚本或者shell命令,linux的tail,top,ps持续的命令,通过管道实时监听,展示在网页上,做成一个外部监控器(process应用)

task执行一个长耗时任务,

两者有重叠但是也有区别

 

本文来自博客园,作者:孙龙-程序员,转载请注明原文链接:https://www.cnblogs.com/sunlong88/p/8996799.html

posted on 2018-05-05 23:41  孙龙-程序员  阅读(273)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3