概述
php8 (php8 >= 8.1.0 ) 中新增了纖程特性,官方文檔地址如下:
https://www.php.NET/manual/zh/language.fibers.php
本文將講解這個新特性的一些簡單使用
基本概念
摘自官方文檔
纖程(Fiber)表示一組有完整棧、可中斷的功能。 纖程可以在調用堆棧中的任何位置被掛起,在纖程內暫停執行,直到稍后恢復。
纖程可以暫停整個執行堆棧,所以該函數的直接調用者不需要改變調用這個函數的方式。
你可以在調用堆棧的任意地方使用 Fiber::suspend() 中斷執行(也就是說,Fiber::suspend() 的調用位置可以在一個深度嵌套的函數中,甚至可以不存在)。
與無棧的 Generator 不同, 每一個 Fiber 擁有自己的調用棧,并允許在一個深度嵌套的函數調用中將它們暫停。 聲明了中斷(interruption)點的函數(即調用 Fiber::suspend()) 不需要改變自己的返回類型,不像使用 yield 一樣需要返回一個 Generator 實例。
纖程可以在任意函數調用中被暫停,包括那些在 PHP VM 中被調用的函數。 例如被用于 array_map() 的函數或者提供 Iterator 實例以被 foreach 調用的方法。
纖程一旦被暫停,可以使用 Fiber::resume() 傳遞任意值、或者使用 Fiber::throw() 向纖程拋出一個異常以恢復運行。這個值或者異常將會在 Fiber::suspend() 中被返回(拋出)。
基本使用
<?php
// 聲明一個纖程
$fiber = new Fiber(function (): void {
echo 'fiber is start now ' . PHP_EOL;
// 使纖程暫停,并拋出值 ‘suspend value’,可以被外部接收
$value = Fiber::suspend('suspend value '); // 接收到 first
echo 'fiber is resume now ' . PHP_EOL;
// 第二次暫停
$value = Fiber::suspend("the second time"); // 接收到 second
echo 'fiber is finish now ' . PHP_EOL;
});
// 纖程開始執行,并且拿到暫停時拋出的值
$res = $fiber->start(); // fiber is start now
echo "fiber start:{$res} " . PHP_EOL; // fiber start:suspend value
echo "fiber status:{$fiber->isSuspended()} " . PHP_EOL; // fiber status:1
echo "fiber status:{$fiber->isRunning()} " . PHP_EOL; // fiber status:
echo "fiber status:{$fiber->isStarted()} " . PHP_EOL; // fiber status:1
echo "fiber status:{$fiber->isTerminated()} " . PHP_EOL; // fiber status:
// 恢復fiber運行
$res2 = $fiber->resume('first'); // fiber is resume now
// 恢復運行時拿到的 $res2 是下一次暫停給出的值
echo "fiber resume:{$res2} " . PHP_EOL; // fiber resume:the second time
// 再次恢復 fiber 運行
$res3 = $fiber->resume('second'); // fiber is finish now
// 此時 $fiber實際上已經結束,拿到的 $res3,是個NULL
var_dump($res3); // NULL
// 此時已經結束,再次調用會爆出 PHP Fatal Error
$res4 = $fiber->resume(); // PHP Fatal error: Uncaught FiberError: Cannot resume a fiber that is not suspended
// 因此一般可以進行一次判斷
if($fiber->isSuspended()){
$res = $fiber->resume();
}
問題
一、纖程如果沒有執行結束,當腳本執行完畢時,會不會被釋放?
理論上來說PHP仍然是單線程在執行,一旦腳本結束,纖程沒有執行的部分依然會被釋放
二、纖程是異步執行的嗎?
我認為纖程仍然是個同步執行的過程,尤其是Fiber本身能力的執行,尤其是以上這個例子。
但是從官方文檔中可知,纖程有獨立的調用棧,允許在棧中任意地方中斷;
只要封裝的足夠好,不難實現異步的能力,當然具體的實現還沒有深入去思考
三、纖程在具體業務上有場景使用嗎?
目前我還沒有想到能夠直接使用纖程的具體業務場景
能想到的都是比較抽象的場景,要經過多層封裝之后當做工具庫進行使用
從纖程的特性及能力來說,幾乎就是一個加強版的生成器(Generator),理論上來說以前基于生成器所做的那些工具庫(或者框架?),都能用纖程來進行更好的實現,拭目以待。
總結
從以上簡單的調用和問題上來看
新特性纖程在業務上能夠使用的場景并不多
可能更多是作為一些比較底層的能力封裝支撐,例如異步執行庫、事件循環庫等
希望很快這個特性會出現在各種框架里面