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






