当前位置: 首页 > news >正文

php方案 PHP 实现协程调度器

两个方向:用 Swoole(生产)或纯PHPGenerator 手写(理解原理)。---方向一:Swoole 协程(生产首选) docker run--rm phpswoole/swoole php coroutine.php<?php// coroutine.phpuseSwoole\Coroutine;useSwoole\Coroutine\WaitGroup;useSwoole\Coroutine\Channel;Coroutine\run(function(){// ===== 基础:并发HTTP请求 =====$wg=newWaitGroup();$results=[];foreach(['https://httpbin.org/delay/1','https://httpbin.org/delay/1']as$i=>$url){$wg->add();Coroutine::create(function()use($wg,&$results,$i,$url){$cli=newCoroutine\Http\Client('httpbin.org',443,true);$cli->get('/delay/1');$results[$i]=$cli->statusCode;$wg->done();});}$wg->wait();// 两个请求并发,总耗时≈1秒而非2秒var_dump($results);// ===== Channel:协程间通信(生产者/消费者)=====$ch=newChannel(5);// 缓冲区5// 生产者Coroutine::create(function()use($ch){for($i=0;$i<5;$i++){$ch->push("任务$i");echo"生产: 任务$i\n";}$ch->close();});// 消费者Coroutine::create(function()use($ch){while(($task=$ch->pop())!==false){echo"消费:$task\n";Coroutine::sleep(0.1);// 模拟处理,不阻塞其他协程}});// ===== 协程池:控制并发数 =====$pool=newCoroutine\Pool(10);// 最多10个并发$tasks=range(1,50);$wg2=newWaitGroup();foreach($tasksas$task){$wg2->add();$pool->submit(function()use($task,$wg2){Coroutine::sleep(0.01);echo"完成任务$task\n";$wg2->done();});}$wg2->wait();echo"全部完成\n";});---方向二:纯PHPGenerator 手写调度器(理解原理)<?php// 不依赖任何扩展,用Generator模拟协程// ===== Task:包装一个Generator =====classTask{privatestaticint$idGen=0;publicint$id;publicbool$finished=false;publicfunction__construct(private\Generator$gen){$this->id=++self::$idGen;}publicfunctionrun():mixed{$val=$this->gen->current();// 取yield的值$this->gen->next();// 推进到下一个yield$this->finished=!$this->gen->valid();return$val;}}// ===== Scheduler:任务队列 + 调度循环 =====classScheduler{private\SplQueue$queue;privatearray$ioWaiting=[];// 等待IO的任务publicfunction__construct(){$this->queue=new\SplQueue();}publicfunctionadd(\Generator$gen):void{$this->queue->enqueue(newTask($gen));}publicfunctionrun():void{while(!$this->queue->isEmpty()||!empty($this->ioWaiting)){// 检查IO就绪(模拟事件循环)$this->pollIO();if($this->queue->isEmpty())continue;$task=$this->queue->dequeue();$syscall=$task->run();// 运行到下一个yieldif($task->finished){echo"[Task{$task->id}] 完成\n";continue;}// 处理系统调用(yield返回的特殊指令)if($syscallinstanceofSysCall){$syscall->execute($task,$this);}else{$this->queue->enqueue($task);// 普通yield,重新入队}}}publicfunctionschedule(Task$task):void{$this->queue->enqueue($task);}// 模拟非阻塞IO等待publicfunctionwaitIO(Task$task,string$resource):void{$this->ioWaiting[$resource]=$task;}privatefunctionpollIO():void{foreach($this->ioWaitingas$resource=>$task){// 模拟IO完成(实际应用用stream_select)unset($this->ioWaiting[$resource]);$this->queue->enqueue($task);}}}// ===== SysCall:协程与调度器通信的信号 =====classSysCall{publicfunction__construct(private\Closure$fn){}publicfunctionexecute(Task$task,Scheduler$scheduler):void{($this->fn)($task,$scheduler);}}// 系统调用:获取当前任务IDfunctiongetTaskId():SysCall{returnnewSysCall(fn(Task$t,Scheduler$s)=>$t->run()// 把ID传回给协程(通过Generator::send));}// 系统调用:创建新协程functionnewTask(\Generator$gen):SysCall{returnnewSysCall(function(Task$t,Scheduler$s)use($gen){$s->add($gen);$s->schedule($t);});}// 系统调用:主动让出CPUfunctionyieldCpu():SysCall{returnnewSysCall(fn(Task$t,Scheduler$s)=>$s->schedule($t));}// ===== 使用示例 =====functiontaskA():\Generator{echo"[A] 开始\n";yieldyieldCpu();// 主动让出,让其他协程跑echo"[A] 恢复,创建子任务\n";yieldnewTask(taskC());// 动态创建新协程echo"[A] 结束\n";}functiontaskB():\Generator{echo"[B] 开始\n";for($i=0;$i<3;$i++){echo"[B] 第$i次循环\n";yieldyieldCpu();// 每次循环让出一次}echo"[B] 结束\n";}functiontaskC():\Generator{echo"[C] 子任务执行\n";yield;echo"[C] 子任务完成\n";}$scheduler=newScheduler();$scheduler->add(taskA());$scheduler->add(taskB());$scheduler->run();输出(交替执行,非顺序):[A]开始[B]开始[B]0次循环[A]恢复,创建子任务[B]1次循环[C]子任务执行[B]2次循环[A]结束[C]子任务完成[B]结束---大白话解释 进程/线程: 每个任务一个线程 线程切换要进内核,贵(微秒级) 内存占用大(每线程8MB栈) 协程: 所有任务在一个线程里 切换在用户态,便宜(纳秒级) 内存小(每协程几KB) 调度器干的事: 任务A跑到一半 → 遇到IO等待 → 主动yield让出CPU→ 调度器把任务B拿出来跑 →IO好了 → 任务A重新入队 → 调度器再把A拿出来继续跑 就像餐厅服务员: 不是一直盯着一桌客人等他们点完菜 而是把菜单留下,去服务其他桌 客人想好了再叫你 Generator原理:functionfoo(){echo"第一段\n";yield;// ← 暂停点,把控制权交出去echo"第二段\n";yield;// ← 再次暂停echo"第三段\n";}// 调度器可以在任意yield处切换到其他任务Swoole vs 纯PHP: 纯PHPGenerator:理解原理用,无法真正并发IOSwoole:Hook了所有IO函数,遇到网络/文件IO自动切换,真正并发
http://www.jsqmd.com/news/480619/

相关文章:

  • Python小白必做的30道基础练习题
  • Python 变量和数据类型
  • 探讨2026年全屋定制MES软件,如何选择合适的产品 - 工业推荐榜
  • 2026年GEO优化靠谱公司有哪些,鸿犀智能口碑出众 - mypinpai
  • 最近爆火的OpenClaw到底是什么?一文读懂RAG、MCP
  • Java 部署:Jenkins Pipeline 构建 Java 项目(自动化)
  • AWE 2026:“新人车家”时代,机器人引领家电消费新变革
  • 2026 AWE:具身智能机器人开启家庭服务新时代
  • 大树科技电话查询:综合技术驱动型服务客观解析 - 品牌推荐
  • 【开源-Proteus8.9仿真】基于51单片机的四相步进电机控制(ULN2003 + StepMotor + LCD1602) - 少年
  • 腾讯“龙虾”产品矩阵出击,AI 市场风云再起
  • 2026年盘点弗拉门戈舞蹈教学机构,深圳西艺文化口碑怎么样 - mypinpai
  • 总结津胜GEO优势,看看在天津地区使用它靠不靠谱 - 工业品网
  • 汽车贴膜性价比怎么选,肇庆星车驾到这样的公司靠谱吗 - 工业设备
  • 探讨不错的瓷砖建材采购企业,潮州哪家口碑好且费用合理? - 工业品牌热点
  • 说说中欧班列货代品牌企业,珠三角地区哪家口碑比较好? - 工业设备
  • 2026年讲讲津胜GEO,其员工素质能满足服务需求吗 - 工业品牌热点
  • 上海百达翡丽/北京江诗丹顿/杭州爱彼维修推荐?六大城市高端腕表维修全解析 - 时光修表匠
  • 优优推电话查询:了解其服务内容与联系渠道 - 品牌推荐
  • GitHub 热榜项目 - 日榜(2026-03-15)
  • 探讨佛山蓝色防滑漆选购要点,哪个品牌更值得入手 - myqiye
  • 2026年专科生必看!学生热捧的降AIGC平台 —— 千笔·专业降AI率智能体
  • InStreet API 完整参考
  • 专科生也能用!千笔,倍受青睐的AI论文写作软件
  • 选购GEO优化方案,上海地区好用的有哪些 - myqiye
  • 【AI应用出海】
  • 【69页PPT】全生命周期数字健康智慧医共体解决方案:“1”朵健康云、“3”大核心应用、“N”类服务应用迭代、区域医院智慧管理平台...
  • 学长亲荐!AI论文平台 千笔ai写作 VS speedai,专科生写论文更轻松!
  • 优优推电话查询:营销服务风险提示与咨询 - 品牌推荐
  • CF1363D Guess The Maximums 题解