本文先介紹了生成器的概念,重點是yield的用法及生成器的介面。協程部分則簡單說了協程的原理,以及PHP協程編程中應注意的事項。
PHP自5.5起引進了生成器(Generator),基於其可實現協程程式設計。本文先回顧生成器,然後再過渡到協程程式設計。
yield與生成器
生成器
生成器是一種資料類型,實作了iterator介面。不能透過new得到生成器實例,也沒有取得生成器實例的靜態方法。得到生成器實例的唯一方法是呼叫生成器函數(包含yield關鍵字的函數)。呼叫生成器函數直接傳回一個生成器對象,生成器運行時函數內的程式碼才開始執行。
先上程式碼直覺地感受一下yield與生成器:
# generator1.php function foo() { exit('exit script when generator runs.'); yield; } $gen = foo(); var_dump($gen); $gen->current(); echo 'unreachable code!'; # 执行结果 object(Generator)#1 (0) { } exit script when generator runs.
foo
函數包含yield
關鍵字,變身為生成函式。呼叫foo
不會執行函數體中的任何程式碼,而是傳回一個生成器實例。生成器運行後,foo
函數內的程式碼執行,腳本結束。
如其名,生成器可以用來產生資料。只是其生成數據的方式與其他函數不一樣:生成器通過yield
返回數據,而非return
; yield
返回數據後,生成器函數不會銷毀,只是暫停運行,未來可以從暫停處恢復運行;生成器運行一次,(只)返回一個數據,多次運行就返回多個數據;不調用生成器獲取數據,生成器內的代碼就躺著不動,所謂動次打次,說的就是生成器產生資料的樣子。
生成器實作了迭代器接口,取得生成器資料可以用foreach
循環或手動current/next/valid
。如下程式碼示範資料產生和遍歷:
# generator2.php function foo() { # 返回键值对数据 yield "key1" => "value1"; $count = 0; while ($count valid()) { fwrite(STDOUT, "key:{$gen->key()}, value:{$gen->current()}\n"); $gen->next(); } # foreach 遍历数据 fwrite(STDOUT, "\ndata from foreach\n"); foreach (foo() as $key => $value) { fwrite(STDOUT, "key:$key, value:$value\n"); }
yield
yield
關鍵字是產生器的核心,其讓普通函數異化(進化)為產生器函數。 yield
有「讓出」的意思,程式執行到yield
語句會暫停執行,讓出CPU並將控制權傳回呼叫者,下次執行時從中斷點繼續執行。控制權回到呼叫者時,yield
語句可以攜帶值回傳給呼叫方。 generator2.php
腳本示範了yield傳回值的三種形式:
yield $key => $value: 傳回資料的key和value;
yield $value: 傳回數據,key由系統指派;
yield: 傳回null值,key由系統指派;
##yield
讓函數可以隨時暫停、繼續執行,並傳回資料給呼叫方。如果繼續執行時需要外部數據,這個工作由生成器的send
函數提供:出現在yield
左邊等號的變數會接收send
傳來的值。看一個常見的send
函數使用範例:
function logger(string $filename) { $fd = fopen($filename, 'w+'); while($msg = yield) { fwrite($fd, date('Y-m-d H:i:s') . ':' . $msg . PHP_EOL); } fclose($fd); } $logger = logger('log.txt'); $logger->send('program starts!'); // do some thing $logger->send('program ends!');
send
讓生成器之間和外部有雙向資料通訊的能力:yield
返回資料;send
提供繼續運行的支撐資料。由於send
讓生成器繼續執行,這個行為與迭代器的next
介面類似,next
相當於send(null)
。
其他
$string = yield $data;
的表達式在PHP7前不合法,需要加括號:$string = (yield $data)
;PHP5生成器函數不能
return
值,PHP7後可以return值,並且經過生成器的getReturn
取得傳回的值。PHP7新增了
yield from
語法,實作了生成器委託。生成器是單向迭代器,開啟後無法呼叫
rewind
。
總結
相對於其他迭代器,生成器具有效能開銷小、編碼容易的特性。其角色主要體現在三個面向:
資料產生(生產者),透過yield回傳資料;
資料消費(消費者),消費send傳來的資料;
實現協程。
關於PHP中的生成器及基本用法,建議看看 2gua 大佬的博文:PHP之生成器,生動有趣且易懂。
協程程式設計
協程(coroutine)是隨時可中斷、恢復執行的子程序,yield
關鍵字讓函數擁有這種能力,所以可以用於協程編程。
行程、執行緒與協程
執行緒歸屬於行程,一個行程可有多個執行緒。進程是電腦分配資源的最小單位,執行緒是電腦調度執行的最小單位。行程和執行緒均由作業系統調度。
協程可以看成“用戶狀態的執行緒”,需要使用者程式實現調度。執行緒和進程由作業系統調度「搶佔式」交替運行,協程主動讓出CPU「協商式」交替運行。協程十分的輕量,協程切換不涉及執行緒切換,執行效率高,數目越多,越能體現協程的優勢。
生成器和協程
生成器實現的協程屬於無堆疊協程(stackless coroutine),即生成器函數只有函數幀,運行時附加到呼叫方的棧上執行。有別於功能強大的有棧協程(stackful coroutine),生成器暫停後無法控製程式走向,只能將控制權被動的歸還呼叫者;生成器只能中斷自身,不能中斷整個協程。當然,生成器的好處便是效率高(暫停時只需儲存程式計數器即可),實作簡單。
協程編程
說到PHP中的協程編程,相信大部分人已經看過鳥哥轉載(翻譯)的這篇博文:在PHP中使用協程實現多任務調度。原文作者 nikic 是PHP的核心開發者,生成器功能的倡議者和實作人。想深入了解生成器及基於其的協程編程,nikic關於生成器的RFC和鳥哥網站上的文章必讀。
先看看基於生成器的協程工作方式:協程協作式工作,即協程之間透過主動讓出CPU達到多任務交替運行(即並發多任務,但不是並行);一個生成器可看成一個協程,執行到yield
語句,讓出CPU控制權回到呼叫方,呼叫方繼續執行其他協程或其他程式碼。
再來看鳥哥部落格理解的難點何在。協程非常輕量,一個系統中可以同時存在成千上萬個協程(生成器)。而作業系統不會對協程調度,安排協程執行的工作就落在開發者身上。部分人看不懂鳥哥文章的協程部分,是因為裡面說協程程式設計少(寫協程主要就是寫生成函數),而是花筆墨實現了一個協程的調度器(scheduler或kernel) :模擬了作業系統,並對所有協程進行公平調度。 PHP發展一般的思考是:我寫了這些程式碼,PHP引擎會呼叫我這些程式碼得到預期結果。而協程程式設計不僅要寫工作的程式碼,還要寫指導這些程式碼什麼時候工作的程式碼。沒有很好的掌握作者的思維,要理解自然會難一些。需要自行調度,這是生成器協程相對於原生協程(async/await形式)的缺點。
知道了協程是怎麼回事,那它能用來幹嘛?協程自行讓出CPU來協作高效利用CPU,讓出的時機當然應該是程式阻塞時。什麼地方會讓程式阻塞呢?使用者態的程式碼鮮有阻塞,阻塞主要是系統呼叫。而係統呼叫的大頭是IO,所以協程的主要應用場景在網路編程。為了讓程式高效能、高並發,程式應該非同步執行不能阻塞。既然非同步執行,就需要通知和回調,寫回調函數避免不了「回呼地獄(callback hell)」的問題:程式碼可讀性差,程式執行流程散落在層層回呼函數中等。解決回調地獄的方式主要有兩種:Promise和協程。協程能以同步的方式編寫程式碼,在高效能網路程式設計(IO密集型)中是推薦的。
再回過頭看PHP中的協程程式設計。 PHP中基於生成器實作協程編程,優先推薦使用RecoilPHP
、Amp
等協程框架。這些框架已經寫好了調度器,在其上開發直接寫入生成器函數,內核會自動調度執行(想讓一個函數以協程方式調度執行,在函數體內加上yield
即可)。如果不想用yield
方式進行協程編程,推薦swoole
或其衍生框架,能做到類似golang的協程編程體驗,又能享受PHP的開發效率。
如果想用原始生態的做PHP協程編程,類似鳥哥博客中的調度器必不可少。調度器調度協程執行,協程中斷後控制權又回到調度器。所以調度器應該總是在主(事件)循環中,也就是CPU不在執行協程,就應該是執行調度器的程式碼。無協程運作時,調度器應當自我阻塞避免消耗CPU(鳥哥部落格中使用了內建的select
系統呼叫),等待事件到來再執行對應的協程。程式運行期間,除了調度器阻塞,協程在運行過程中不應該呼叫阻塞API。
總結
在協程程式設計中,yield
的主要作用是將控制權轉讓,無須糾結於其傳回值(基本上yield
傳回的值會在下次執行時直接send
過來)。重點應關注控制權移轉的時機,以及協程的運作方式。
另外需要說明一點,協程和非同步沒有太大關係,還要看運行環境支撐。常規的PHP運作環境,即使用了promise/coroutine,也仍是同步阻塞的。再屌的協程框架,sleep
一下也不好使了。作為類比,即使JavaScript不使用promise/async這些技術,也是非同步非阻塞的。
透過生成器和Promise,能實現類似await
的協程編程,相關程式碼在Github上很多,本文不再給出。
相關推薦:
PHP中的output_buffering詳細介紹,outputbuffering_PHP教學
#以上是php中協程的詳細介紹(程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

随着传统的多线程模型在高并发场景下的性能瓶颈,协程成为了PHP编程领域的热门话题。协程是一种轻量级的线程,能够在单线程中实现多任务的并发执行。在PHP的语言生态中,协程得到了广泛的应用,比如Swoole、Workerman等框架就提供了对协程的支持。那么,如何在PHP中使用协程呢?本文将介绍一些基本的使用方法以及常见的注意事项,帮助读者了解协程的运作原理,以

近年来,随着互联网应用的日益普及,各种高并发的场景也越来越常见。在这种情况下,传统的同步I/O方式已经无法满足现代应用对高性能、高并发的需求。因此,协程成为了一种被广泛应用的解决方案。Swoole是一款面向高并发、高性能的PHP网络通信框架,可以轻松实现异步、协程等特性。swoole_smtp_auth函数是其中一个常用的函数,它可以在使用SMTP协议进行邮

如果你需要访问多个服务来完成一个请求的处理,比如实现文件上传功能时,首先访问Redis缓存,验证用户是否登录,再接收HTTP消息中的body并保存在磁盘上,最后把文件路径等信息写入MySQL数据库中,你会怎么做?首先可以使用阻塞API编写同步代码,直接一步步串行即可,但很明显这时一个线程只能同时处理一个请求。而我们知道线程数是有限制的,有限的线程数导致无法实现上万级别的并发连接,过多的线程切换也抢走了CPU的时间,从而降低了每秒能够处理的请求数量。于是为了达到高并发,你可能会选择一

随着Web应用程序的迅速发展,开发者们不仅要关注应用程序的功能和可靠性,还要考虑应用程序的性能。而数据库操作一直是Web应用程序的一个瓶颈之一。传统的数据库查询方式通常是通过多线程或者多进程来实现,这个方法效率低下,而且不容易管理。而Swoole的协程特性可以用来优化数据库查询,并提高应用程序的性能。Swoole是一款PHP的高性能网络框架。它有一个非常重要

近年来,随着移动互联网、云计算、大数据等新技术的快速发展,越来越多的企业开始使用PHP构建高并发、高性能的Web应用程序。而传统的LAMP(Linux、Apache、MySQL、PHP)架构,难以满足当前互联网快速发展的需求,因此出现了一些新的PHP框架和工具,比如Swoole。Swoole是一个PHP的网络通信框架,具有协程、异步IO、多进程等优势,可以帮

区别:1、一个线程可以多个协程,一个进程也可以单独拥有多个协程;2、线程是同步机制,而协程则是异步;3、协程能保留上一次调用时的状态,线程不行;4、线程是抢占式,协程是非抢占式的;5、线程是被分割的CPU资源,协程是组织好的代码流程,协程需要线程来承载运行。

Go语言中的协程和select语句的联系是什么?随着计算机的发展,我们对于并发编程的需求也越来越迫切。然而,传统的并发编程方法——基于线程和锁——也逐渐变得复杂并容易出错。为了解决这些问题,Go语言引入了一种新的并发编程模型——协程。协程是由语言自己调度的轻量级线程,在协程中,代码的执行是基于非抢占式的协作式调度的,换句话说,每个协程都会执行一段代码

随着互联网应用的普及,越来越多的应用需要面对高并发的挑战。传统的线程池或进程池方式已经不能满足这种情况下的需求。协程编程技术成为了一种解决高并发问题的有效方式,而Swoole则是目前应用最广泛的协程框架之一。本文将介绍协程编程的基本概念和原理,以及如何使用Swoole框架进行高并发接口设计。我们将以一个简单的Web服务为例,分步骤介绍如何使用协程和Swool


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

禪工作室 13.0.1
強大的PHP整合開發環境