Easyswoole的WaitGroup和Csp组件的分析和使用

easyswoole可真是个好名字,只是提供了恰到好处的封装,即使是源码也保持了这样的风格。这种风格不论好坏可能都需要各位适应下,哈哈。下面一起来感受下es中的实现吧。

-waitgroup在easyswoole中的实现和使用

-csp在easyswoole中的实现和使用

waitgroup

分析
<?php

namespace EasySwoole\Component;

use Swoole\Coroutine\Channel;

class WaitGroup
{
private $count = 0;
/** @var Channel */
private $channel;
private $success = 0;
private $size; public function __construct(int $size = 128)
{
$this->size = $size;
// 主要的初始化功能在reset中 提供了一个传递任务执行情况的通道
// reset方法 还允许在当前协程多次使用同一个waitgroup变量
$this->reset();
} public function add()
{
// wg中子任务的计数器
$this->count++;
} function successNum(): int
{
return $this->success;
} public function done()
{
// 当子协程任务执行完毕时 向管道中push了一个int 1
$this->channel->push(1);
} // 最主要的逻辑在这里
// 其中的while循环 相当于在主协程中阻塞 直到全部的任务执行完成或者超时
public function wait(?float $timeout = 15)
{
if ($timeout <= 0) {
$timeout = PHP_INT_MAX;
}
$this->success = 0;
$left = $timeout;
// $this->count是还要等待完成的子协程数量
// $left是超时时间 即主协程继续向下执行还需要等待的时间(其实并不存在主子协程的概念 这里只是为了好区分)
// 当add的任务全部执行完成 或者 超过了设置的timeout 此wait函数执行完毕 程序继续向下执行
while (($this->count > 0) && ($left > 0)) {
$start = round(microtime(true), 3);
if ($this->channel->pop($left) === 1) {
// 每从通道pop一次就给还要执行的任务数量-1
$this->count--;
// 每从通道pop一次就给成功数量+1
$this->success++;
}
// 每循环一次更新一次还要wait的时间
$left = $left - (round(microtime(true), 3) - $start);
}
} function reset()
{
$this->close();
$this->count = 0;
$this->success = 0;
$this->channel = new Channel($this->size);
} function close()
{
if ($this->channel) {
$this->channel->close();
$this->channel = null;
}
} function __destruct()
{
$this->close();
}
}
使用
# 确保开起了swoole的协程hook
$wg = new WaitGroup();
$wg->add();
go(function () use ($wg) {
defer(function () use ($wg) {
$wg->done();
});
sleep(1); # 子协程使用sleep模拟阻塞
var_dump("task1 done");
});
$wg->add();
go(function () use ($wg) {
defer(function () use ($wg) {
$wg->done();
});
sleep(5); # 子协程使用sleep模拟阻塞
var_dump('task2 done');
});
# 调用了wait方法 主协程就阻塞在wait方法中的while循环上 直到全部的子协程执行完毕或者超时才执行后面的代码
$wg->wait(); # 可以尝试在wait中传递较小的超时时间 检查效果
var_dump('main task done'); # 给出swoole协程切换的条件
1 协程中的代码遇到阻塞 如上的sleep
2 协程主动yield让出执行权
3 cpu计算超时 主动让出执行权(详细配置请查看swoole官方文档)
其他的切换条件请大家补充

csp

分析
<?php

namespace EasySwoole\Component;

use Swoole\Coroutine\Channel;
use Swoole\Coroutine; class Csp
{
private $chan;
private $count = 0;
private $success = 0;
private $task = []; // 初始化channel
function __construct(int $size = 8)
{
$this->chan = new Channel($size);
} // 添加要并发执行的任务
function add($itemName, callable $call): Csp
{
$this->count = 0;
$this->success = 0;
$this->task[$itemName] = $call;
return $this;
} function successNum(): int
{
return $this->success;
} // 阻塞执行添加的任务 直到全部执行完毕 或者 超时
function exec(?float $timeout = 5)
{
if ($timeout <= 0) {
$timeout = PHP_INT_MAX;
}
$this->count = count($this->task);
// 创建协程并发执行add进来的任务
foreach ($this->task as $key => $call) {
Coroutine::create(function () use ($key, $call) {
// 调用add进来的闭包
$data = call_user_func($call);
// 将执行结果送入通道
$this->chan->push([
'key' => $key,
'result' => $data
]);
});
}
$result = [];
$start = microtime(true);
// 同样是通过while循环 将代码阻塞在exec方法上
while ($this->count > 0) {
// 超时返回false
$temp = $this->chan->pop(1);
if (is_array($temp)) {
$key = $temp['key'];
$result[$key] = $temp['result'];
$this->count--;
$this->success++;
}
// 超时就结束循环 代码向下执行
if (microtime(true) - $start > $timeout) {
break;
}
}
return $result;
}
}
使用
# 执行发现并没有先打印主协程中的 main task done,这是因为Csp的exec方法会阻塞当前协程

$csp = new Csp();
$csp->add('task1', function () {
return file_get_contents("https://www.easyswoole.com/Cn/Components/Component/csp.html");
});
$csp->add('task2', function () {
return file_get_contents("https://www.easyswoole.com/Cn/Components/Component/waitGroup.html");
});
$res = $csp->exec();
var_dump($res);
go(function () {
var_dump("main task done");
}); # 如此使用触发了协程调度 导致先输出了主协程的main task done go(function () {
$csp = new Csp();
$csp->add('task1', function () {
return file_get_contents("https://www.easyswoole.com/Cn/Components/Component/csp.html");
});
$csp->add('task2', function () {
return file_get_contents("https://wiki.swoole.com/#/start/start_tcp_servers");
});
$res = $csp->exec();
var_dump($res);
});
var_dump('main task done'); # 有时候可能需要将csp放到自行创建的协程容器中执行 可以尝试下面配合WaitGroup的方式
$wg = new WaitGroup();
$wg->add();
go(function () use ($wg) {
defer(function () use ($wg) {
$wg->done();
});
$csp = new Csp();
$csp->add('task1', function () {
return file_get_contents("https://www.easyswoole.com/Cn/Components/Component/csp.html");
});
$csp->add('task2', function () {
return file_get_contents("https://www.easyswoole.com/Cn/Components/Component/waitGroup.html");
});
$res = $csp->exec();
var_dump($res);
});
$wg->wait();
// go(function(){
// var_dump('main task done');
// });
var_dump('main task done');
请勿将以上的代码搬运到go中,因为golang在语言层面完全支持了协程调度,而swoole的协程不仅需要在协程容器中使用,并且实现协程的切换也需要相应的条件。

今天就说到这吧,发现错误欢迎指正,感谢!!!

Easyswoole的WaitGroup和Csp组件的分析和使用的更多相关文章

  1. Tomcat结构、启动过程、关键组件简单分析

                            Tomcat   结构:   Tomcat最顶层容器叫Server,代表整个服务器,Server中包含至少一个Service,用于具体提供服务,Serv ...

  2. Django admin 组件 原理分析与扩展使用 之 sites.py (一)

    一 . 前言 Django 提供了admin 组件 为项目提供基本的管理后台功能(对数据表的增删改查). 本篇文章通过 admin源码 简单分析admin 内部原理 ,扩展使用方式,为以后进行定制和自 ...

  3. Tomcat8源码笔记(五)组件Container分析

    Tomcat8源码笔记(四)Server和Service初始化 介绍过Tomcat中Service的初始化 最先初始化就是Container,而Container初始化过程是咋样的? 说到Contai ...

  4. JS日期级联组件代码分析及demo

    最近研究下JS日期级联效果 感觉还不错,然后看了下kissy也正好有这么一个组件,也看了下源码,写的还不错,通过google最早是在2011年 淘宝的虎牙(花名)用原审JS写了一个(貌似据说是从YUI ...

  5. WeUI Picker组件 源代码分析

    前言 由于最近做的一个移动端项目需要使用到类似 WeUI Picker组件 的选择效果,  所以在这里来分析下 WeUI Picker 的实现逻辑.(weui.js项目地址) 之前也做过类似的组件, ...

  6. 基于Apache组件,分析对象池原理

    池塘里养:Object: 一.设计与原理 1.基础案例 首先看一个基于common-pool2对象池组件的应用案例,主要有工厂类.对象池.对象三个核心角色,以及池化对象的使用流程: import or ...

  7. 基于HiKariCP组件,分析连接池原理

    HiKariCP作为SpringBoot2框架的默认连接池,号称是跑的最快的连接池,数据库连接池与之前两篇提到的线程池和对象池,从设计的原理上都是基于池化思想,只是在实现方式上有各自的特点:

  8. 对.net技术组件的分析和选择

    .net很庞杂,学习最忌讳什么?为了学而学,而不是为了用而学.我们不是为了成为教师,所以不要成为书呆子,不要成为"博士",要从庞杂的技术群中选择自己需要的内容进行学习. 如果不加选 ...

  9. window2008 64位系统没有office组件问题分析及解决

    服务器是windows server2008 64位系统, 我的系统需要用到Microsoft.Office.Interop.Excel组件 在上传Excel单据遇到错误:检索 COM 类工厂中 CL ...

随机推荐

  1. 把VS Code打造成Java开发IDE

    近期,公司推行正版化,本人使用的是JetBrains教育版,是不允许进行商业开发的,因此开启了艰难的备用IDE选型之路.最终,我选定了轻量级的Visual Studio Code(以下简称VS Cod ...

  2. Mac更换鼠标指针样式_mousecape教程

    mousecape项目介绍 这是github上的一个项目,作者是alexzielenski. 项目是用于修改Mac系统鼠标样式的,支持动态鼠标样式. 该项目停止更新于2014年,目前仍可以被较新的系统 ...

  3. Excel文件内容无法显示解决方案

    问题描述: 双击打开一个excel文件,内容无显示,只能通过"打开"选项,选择文件,才能正常显示. 解决方法一: 1.[win+R]打开快速访问,输入"regedit&q ...

  4. 【PowerQuery】做了一万遍的工资条

    前面已经了解了Excel.VBA.Python实现工资条,今天尝试用PQ做一遍 做之前迷惑了很久,如何能自定义长度 Table有Repeat函数,但是List没有.看来另外想办法 一步步接近目标  请 ...

  5. 1、了解JVM

    1.JVM.JRE.JDK JVM:是可以将要运行的程序编译成机器语言并去执行的一个平台,具有跨语言.跨平台的特性,运行时需要依赖JRE中的类库 JRE:包含了JVM以及代码运行时的类库,时Java程 ...

  6. Power Designer建模之餐饮在线点评系统——业务处理模型

    餐饮在线点评系统除查看会员促销活动.查看站内消息等简单业务流程外,相对复杂的业务流程包括管理员注册餐厅,发布餐厅信息,餐厅信息主要包括特色菜.促销活动.团购活动和优惠券信息. 餐厅信息发布后,用户可以 ...

  7. 成理信安协会反序列化01-利用fastcoll实现md5碰撞

    虽然是反序列化的题目,但主要考点在利用fastcoll实现md5碰撞. 直接上源码 <?php show_source(__FILE__); class CDUTSEC { public $va ...

  8. shell-变量的数值运算-bc-typeset-中括号等方法介绍

    1. bc命令的用法: bc是unix下的计算器,它也可以用在命令行下面:    例:给自变量i加1 i=2 i=`echo $i + 1|bc` --------效率低     因为bc支持科学计算 ...

  9. shell-脚本的执行

    1. shell脚本的执行 当shell脚本以非交互的方式运行时,它会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrc),然后从该环境变量文件开始执行,当读取了ENV文件后,she ...

  10. [tip:,x86/urgent] x86: Fix early boot crash on gcc-10, third try

    [tip:,x86/urgent] x86: Fix early boot crash on gcc-10, third try   https://lore.kernel.org/patchwork ...