hyperf 协程作用和相关的方法

news2024/11/24 20:12:19

什么是协程

协程是一种轻量级的线程,由用户代码来调度和管理,而不是由操作系统内核来进行调度,也就是在用户态进行

判断当前是否处于协程环境内

在一些情况下我们希望判断一些当前是否运行于协程环境内,
对于一些兼容协程环境与非协程环境的代码来说会作为一个判断的依据,
我们可以通过 Hyperf\Coroutine\Coroutine::inCoroutine(): bool 方法来得到结果。

创建协程的三种方式

Hyperf 是运行于 Swoole 4 的协程和 Swow 协程之上的,这也是 Hyperf 能提供高性能的其中一个很大的因素。

1. 通过co/go来创建协程

只需通过 co(callable $callable) 或 go(callable $callable) 函数或 Hyperf\Utils\Coroutine::create(callable $callable) 即可创建一个协程,协程内可以使用协程相关的方法和客户端

co

    public function co()
    {
        co(function () {
            sleep(1);
            echo "hello world 2 \n";
        });
        co(function () {
            sleep(1);
            echo "hello world 3 \n";
        });
    }

在这里插入图片描述

go

 public function go()
    {
        go(function () {
            sleep(2);
            echo "hello world 66 \n";
        });
        go(function () {
            sleep(1);
            echo "hello world 77 \n";
        });
    }

在这里插入图片描述

2. Coroutine::create

    public function coroutine()
    {
        Coroutine::create(function () {
            sleep(1);
            echo "hello world 88 \n";
        });
        Coroutine::create(function () {
            sleep(2);
            echo "hello world 99 \n";
        });
    }

在这里插入图片描述

    public function coroutine()
    {
        $coroutine = new Coroutine();
        $coroutine->create(function () {
            sleep(1);
            echo "hello world 33 \n";
        });
        $coroutine->create(function () {
            sleep(2);
            echo "hello world 44 \n";
        });
    }

在这里插入图片描述

3. 待完善

获得当前协程的 ID


    public function getCoroutineId()
    {
       
       $croutineId =  Coroutine::id();
       return json_encode(['croutineId'=> $croutineId]);
    }

在这里插入图片描述

Channel 通道

什么是channel呢,和go的chan一样,就是获取协程之间的数据通信

Channel 与 PHP 的数组类似,仅占用内存,没有其他额外的资源申请,所有操作均为内存操作,无 I/O 消耗,使用方法与 SplQueue 队列类似。

   public function channal(){
       $chan =  new \Swoole\Coroutine\Channel();
       co(function () use ($chan) {
        $chan->push('I am an alien');
        });
       $data =  $chan->pop();
       return json_encode(['data'=> $data]);
    }

在这里插入图片描述

Defer 特性

当我们希望在协程结束时运行一些代码时,可以通过 defer(callable $callable) 函数或 Hyperf\Coroutine::defer(callable $callable) 将一段函数以 栈(stack) 的形式储存起来,栈(stack) 内的函数会在当前协程结束时以 先进后出 的流程逐个执行。


    public function channal(){
       $chan =  new \Swoole\Coroutine\Channel();
       co(function () use ($chan) {
        $chan->push('I am an alien');
        defer(function(){
            $this->defers();
        });
        });

       $data =  $chan->pop();
       return json_encode(['data'=> $data]);
    }

    public function defers(){
          echo "hello world 111 \n";
    }

在这里插入图片描述
在这里插入图片描述

WaitGroup 特性

WaitGroup 是基于 Channel 衍生出来的一个特性,如果接触过 Go 语言,我们都会知道 WaitGroup 这一特性,在 Hyperf 里,WaitGroup 的用途是使得主协程一直阻塞等待直到所有相关的子协程都已经完成了任务后再继续运行,这里说到的阻塞等待是仅对于主协程(即当前协程)来说的,并不会阻塞当前进程。
我们通过一段代码来演示该特性:

    public function waitGroup(){
        $wg = new \Swoole\Coroutine\WaitGroup();
        $wg->add();
        go(function () use ($wg) {
            sleep(10);
            $wg->done();
        });
        go(function () use ($wg) {
            sleep(5);
            $wg->done();
        });
        $wg->wait();
        echo "hello world 55 \n";
    }

结果:
5秒后才执行主协程的内容

hello world 55

Parallel 特性

Parallel 特性是 Hyperf 基于 WaitGroup 特性抽象出来的一个更便捷的使用方法,我们通过一段代码来演示一下。

<?php
declare(strict_types=1);
namespace App\Controller;

use Hyperf\Utils\Exception\ParallelExecutionException;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\Parallel;

/**
 * @AutoController()
 */
class WaitGroupController extends AbstractController
{
           
    public function index()
    {
 
        $parallel = new Parallel();
        $parallel->add(function () {
            sleep(1);
            return Coroutine::id();
        });
        $parallel->add(function () {
            sleep(1);
            return Coroutine::id();
        });
    
        try{
            // $results 
        $results = $parallel->wait(); 
        return json_encode($results);
        } catch(ParallelExecutionException $e){
            // $e->getResults() 获取协程中的返回值。
            // $e->getThrowables() 获取协程中出现的异常。
            echo $e->getMessage() . PHP_EOL;
        }
    
    }   
}

在这里插入图片描述

上面的代码可以简化成下面的代码

<?php
use Hyperf\Utils\Coroutine;

// 传递的数组参数您也可以带上 key 便于区分子协程,返回的结果也会根据 key 返回对应的结果
$result = parallel([
    function () {
        sleep(1);
        return Coroutine::id();
    },
    function () {
        sleep(1);
        return Coroutine::id();
    }
]);

在这里插入图片描述

限制 Parallel 最大同时运行的协程数

防止访问过大,导致服务器崩溃,可以设置协程同时运行的最大数量
5就是限制数量的

$parallel = new Parallel(5);

完整代码

use Hyperf\Utils\Exception\ParallelExecutionException;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\Parallel;

$parallel = new Parallel(5);
for ($i = 0; $i < 20; $i++) {
    $parallel->add(function () {
        sleep(1);
        return Coroutine::id();
    });
} 

try{
   $results = $parallel->wait(); 
} catch(ParallelExecutionException $e){
    // $e->getResults() 获取协程中的返回值。
    // $e->getThrowables() 获取协程中出现的异常。
}

Concurrent 协程运行控制

Hyperf\Utils\Coroutine\Concurrent 基于 Swoole\Coroutine\Channel 实现,用来控制一个代码块内同时运行的最大协程数量的特性。
以下样例,当同时执行 10 个子协程时,会在循环中阻塞,但只会阻塞当前协程,直到释放出一个位置后,循环继续执行下一个子协程。

<?php

<?php
declare(strict_types=1);
namespace App\Controller;

use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Coroutine\Concurrent;


/**
 * 
 * @AutoController()
 */
class WaitGroupController extends AbstractController
{
           
    public function index()
    {
 

        // 传递的数组参数您也可以带上 key 便于区分子协程,返回的结果也会根据 key 返回对应的结果

        $concurrent = new Concurrent(10);
        
        for ($i = 0; $i < 15; ++$i) {
            $concurrent->create(function () use ($i) {
                // Do something...
                print($i."\n");
            });
        }
        return json_encode( ['success'=>'success','count'=> $concurrent->count()]);
    
    }   
}

在这里插入图片描述
在这里插入图片描述

协程上下文

不能使用传统的php开发,把可变参数放到成员变量里,这样会导致不同协程之间数据混淆
所以出现了 协程上下文里存储可变参数

Hyperf\Utils\Context::set()

通过调用 set(string $id, $value) 方法储存一个值到当前协程的上下文中,如下:

<?php use Hyperf\Utils\Context; // 将 bar 字符串以 foo 为 key 储存到当前协程上下文中 $foo = Context::set('foo', 'bar'); // set 方法会再将 value 作为方法的返回值返回回来,所以 $foo 的值为 bar Copy to clipboardErrorCopied ## Hyperf\Utils\Context::get() 通过调用 get(string $id, $default = null) 方法可从当前协程的上下文中取出一个以 $id 为 key 储存的值,如不存在则返回 $default ,如下: <?php use Hyperf\Utils\Context; // 从当前协程上下文中取出 key 为 foo 的值,如不存在则返回 bar 字符串 $foo = Context::get('foo', 'bar'); Copy to clipboardErrorCopied ## Hyperf\Utils\Context::has() 通过调用 `has(string $id) `方法可判断当前协程的上下文中是否存在以 `$id `为 key 储存的值,如存在则返回 true,不存在则返回 false,如下: ```php <?php use Hyperf\Utils\Context; // 从当前协程上下文中判断 key 为 foo 的值是否存在 $foo = Context::has('foo'); ``` ## Hyperf\Utils\Context::override() 当我们需要做一些复杂的上下文处理,比如先判断一个 key 是否存在,如果存在则取出 value 来再对 value 进行某些修改,然后再将 value 设置回上下文容器中,此时会有比较繁杂的判断条件,可直接通过调用 override 方法来实现这个逻辑,如下: ```php <?php use Psr\Http\Message\ServerRequestInterface; use Hyperf\Utils\Context; // 从协程上下文取出 $request 对象并设置 key 为 foo 的 Header,然后再保存到协程上下文中 $request = Context::override(ServerRequestInterface::class, function (ServerRequestInterface $request) { return $request->withAddedHeader('foo', 'bar'); }); ``` ## Swoole Runtime Hook Level 框架在入口函数中提供了 SWOOLE_HOOK_FLAGS 常量,如果您需要修改整个项目的 Runtime Hook 等级,比如想要支持 CURL 协程 并且 Swoole 版本为 v4.5.4 之前的版本,可以修改这里的代码,如下。 ```php <?php ! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL); ```

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2061669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3568平台(PWM篇)PWM驱动

一.PWM基础知识 PWM 全称为 Pulse Width Modulation&#xff0c;翻译成中文为脉冲宽度调制&#xff0c;它是一种数字信号控 制模拟电路的技术&#xff0c;可以通过改变高/低电平的占空比来控制平均电压或功率,从而达到对模拟 量的控制目的。 周期(T)&#xff1a;指一个完整的…

Vue条件判断:v-if、v-else、v-else-if、v-show 指令

在程序设计中&#xff0c;条件判断是必不可少的技术。在视图中&#xff0c;经常需要通过条件判断来控制 DOM 的显示状态。Vue.js 提供了相应的指令用于实现条件判断&#xff0c;包括&#xff1a;v-if、v-else、v-else-if、v-show 指令。 1、v-if 指令 v-if 指令可以根据表达式…

机器学习 之 线性回归算法

目录 线性回归&#xff1a;理解与应用 什么是线性回归&#xff1f; 一元线性回归 正态分布的重要性 多元线性回归 实例讲解 数据准备 数据分析 构建模型 训练模型 验证模型 应用模型 代码实现 线性回归&#xff1a;理解与应用 线性回归是一种广泛使用的统计方法&…

企业高性能web服务器,原理及实例

一、Web 服务基础介绍 正常情况下的单次web服务访问流程&#xff1a; 1.1 Web 服务介绍 1993年3月2日&#xff0c;中国科学院高能物理研究所租用AT&T公司的国际卫星信道建立的接入美国SLAC国家实 验室的64K专线正式开通&#xff0c;成为我国连入Internet的第一根专线。 1…

Mycat分片-垂直拆分

目录 场景 配置 测试 全局表配置 续接上篇&#xff1a;MySQ分库分表与MyCat安装配置-CSDN博客 续接下篇&#xff1a;Mycat分片-水平拆分-CSDN博客 场景 在业务系统中, 涉及以下表结构 ,但是由于用户与订单每天都会产生大量的数据, 单台服务器的数据 存储及处理能力是有限…

0x01 GlassFish 任意文件读取漏洞复现

参考文章&#xff1a; 应用服务器glassfish任意文件读取漏洞 - SecPulse.COM | 安全脉搏 fofa 搜索使用该服务器的网站 网络空间测绘&#xff0c;网络空间安全搜索引擎&#xff0c;网络空间搜索引擎&#xff0c;安全态势感知 - FOFA网络空间测绘系统 "glassfish"&…

VUE3-nest前后端部署教程-----4.服务器linux中部署Node.js环境

一.安装分布式版本管理系统Git (Alibaba Cloud Linux 3/2、CentOS 7.x) sudo yum install git -y 二.使用Git将NVM的源码克隆到本地的~/.nvm目录下&#xff0c;并检查最新版本。 git clone https://gitee.com/mirrors/nvm.git ~/.nvm && cd ~/.nvm && gi…

仿Muduo库实现高并发服务器——Server.hpp框架的简单描述

EventLoop模块在本项目中的简单使用&#xff1a; 下面这张图 是channel模块&#xff0c;poller模块&#xff0c;TimerWheel模块&#xff0c;EventLoop模块&#xff0c;LoopThreadPool模块进行组合。便于大家对这个项目的理解&#xff0c;因为代码看起来挺复杂的。 下面这个图&…

2024河南萌新联赛第六场题解

这场的出题组是郑州大学acm实验室&#xff0c;验题组是郑州大学和郑州轻工业大学的志愿者同学们。 官方题解大部分内容是我写的&#xff0c;B题思路部分是对应的出题人自己写的&#xff0c;E题思路以及代码都是对应的出题人写的因为我不会写这个题&#xff0c;题目的题面&…

C++--类和对象(三)

本篇主要是填补前两篇类和对象中的小知识点 第一篇:C--类和对象&#xff08;一&#xff09;-CSDN博客 第二篇:C--类和对象&#xff08;二&#xff09;-CSDN博客 目录 1.初始化列表 2.友元&#xff08;friend&#xff09; 3.内部类 1.初始化列表 在之前实现构造函数的时候&a…

uniapp 总结

uniapp的 发送请求的 responseType是没有 blob这个类型的&#xff0c; responseType: ‘arraybuffer’, uniapp 标准js和浏览器js的区别 downloadFile的原理作用

从零开始学习SLAM(五):极几何与极约束

文章参考计算机视觉life 前备知识 概念 几何关系&#xff1a; 上图中&#xff1a; 极平面&#xff08;Epipolar plane&#xff09;&#xff1a;点c0, c1, p三点确定的平面&#xff1b; 极点&#xff08;Epipoles&#xff09;&#xff1a; c0 c1 连线与两个平面的交点 基线&a…

SAP Parallel Accounting(平行分类账业务)配置及操作手册【适用于多国家会计准则】

1. 配置准备 1.1 理解平行账概念 平行账&#xff0c;也称为多分类账&#xff0c;是SAP系统中的一项功能&#xff0c;它允许企业按照不同的会计准则来维护各自的财务数据。这种设置特别适用于那些需要符合多种会计准则的跨国公司。通过平行账&#xff0c;企业可以在不同的分类…

单片机存储芯片 W25QXX、AT24C02

一、FLASH W25QXX (1) W25QXX芯片简介 W25Q128是华邦公司推出的一款SPI接口的NOR Flash芯片&#xff0c;其存储空间为128Mbit&#xff0c;相当于16M字节。W25Q128V芯片是串行闪存&#xff0c;可以通过标准/两线/四线SPI控制。W25Q128一次最多可编程256个字节。页面可以按扇区擦…

特斯拉算法,暴力递归尝试,汉诺塔问题

改进之后的算法 暴力递归就是尝试 汉诺塔问题 主函数 打印一个字符串的全部子序列&#xff0c;包括空字符串

【数据结构题集(c语言版)】内部排序算法比较 题解(起泡排序+直接插入排序+简单选择排序+快速排序+希尔排序+堆排序)

内部排序算法比较 问题描述 在教科书中,各种内部排序算法的时间复杂度分析结果只给出了算法执行时间的阶或大概执行时间。试通过随机数据比较各算法的关键字比较次数和关键字移动次数,以取得直观感受。 基本要求 对以下6种常用的内部排序算法进行比较:起泡排序、直接插入排…

SpringBoot依赖之Spring Data Redis 实现地理坐标(Geospatial)

Spring Boot 项目中使用 Spring Data Redis 实现地理坐标(Geospatial) 概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Sup…

JVM 有哪些垃圾回收器?

JVM 有哪些垃圾回收器&#xff1f; 图中展示了7种作用于不同分代的收集器&#xff0c;如果两个收集器之间存在连线&#xff0c;则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。 新生代收集器&#xff08;全部的都是复制算法&#xff09;&…

使用 Charles 模拟手机弱网测试

在移动互联网时代&#xff0c;网络状况的不确定性给应用程序带来了挑战。尤其是在偏远地区或信号不佳的地方&#xff0c;用户的网络连接可能会变得不稳定。因此&#xff0c;对应用程序进行弱网测试变得尤为重要。Charles Proxy 是一款广泛使用的网络调试工具&#xff0c;它不仅…

分享小诗梦404炫酷单页面html5源码

源码介绍 分享小诗梦404炫酷单页面html5源码&#xff0c;小诗梦的一个很炫酷页面&#xff0c;感觉应该符合一些人的感觉&#xff01;可以用来做404页面。 源码下载 分享小诗梦404炫酷单页面html5源码