佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > Swoole4.4協(xié)程搶占式調(diào)度器詳解

Swoole4.4協(xié)程搶占式調(diào)度器詳解

熱門標(biāo)簽:銀行業(yè)務(wù) 科大訊飛語(yǔ)音識(shí)別系統(tǒng) Mysql連接數(shù)設(shè)置 電子圍欄 服務(wù)器配置 Linux服務(wù)器 阿里云 團(tuán)購(gòu)網(wǎng)站

前言

Swoole內(nèi)核團(tuán)隊(duì)開設(shè)的專欄,會(huì)逐漸投入精力寫文章介紹Swoole的開發(fā)歷程,實(shí)現(xiàn)原理,應(yīng)用實(shí)踐等,大家可以更好的交流,共同學(xué)習(xí),建設(shè)PHP生態(tài)。

協(xié)程調(diào)度

去年Swoole推出了4.0版本后,完整的支持PHP協(xié)程,我們可以基于協(xié)程實(shí)現(xiàn)CSP編程,身邊的開發(fā)者驚呼,原來(lái)PHP代碼還可以這樣寫。Swoole的協(xié)程默認(rèn)是基于IO調(diào)度,程序中有阻塞會(huì)自動(dòng)讓出當(dāng)前協(xié)程,協(xié)程的各種優(yōu)勢(shì)我們不在這里展開討論。如果是IO密集型的場(chǎng)景,可以表現(xiàn)得很不錯(cuò)。但是對(duì)于CPU密集型的場(chǎng)景,會(huì)導(dǎo)致一些協(xié)程因?yàn)榈貌坏?code>CPU時(shí)間片被餓死。

搶占式調(diào)度

我們?cè)诮衲昴瓿蹙陀?jì)劃實(shí)現(xiàn)Swoole的搶占式調(diào)度,以滿足實(shí)現(xiàn)有些場(chǎng)景下的不均衡調(diào)度帶來(lái)的問(wèn)題。我們中間經(jīng)歷了幾個(gè)版本,在這里和大家分享一下開發(fā)過(guò)程中的動(dòng)機(jī)和解決辦法。

我們目的是為了均衡調(diào)度每個(gè)協(xié)程的CPU時(shí)間,比如協(xié)程3需要比較長(zhǎng)的執(zhí)行時(shí)間,我們必須把協(xié)程3的CPU時(shí)間主動(dòng)中斷,而不依賴IO事件,使得每個(gè)協(xié)程得到平均的執(zhí)行時(shí)間。

起初,我們的想法是可以從PHP的循環(huán)中自動(dòng)檢測(cè)執(zhí)行實(shí)踐,若達(dá)到限制,可以自動(dòng)讓出當(dāng)前協(xié)程。因?yàn)楫吘购苌儆腥艘获R平川的寫出占用很多CPU的代碼,大都通過(guò)循環(huán)條件來(lái)控制。我們hook循環(huán)指令,每次執(zhí)行循環(huán)指令的時(shí)候,都來(lái)檢查協(xié)程的執(zhí)行時(shí)間,我們很欣喜的得到了最初的版本。但是這樣做比較hack,而且opcode經(jīng)過(guò)opcache優(yōu)化后,情況會(huì)變得有些復(fù)雜。

后來(lái)我們使用PHPticks機(jī)制,也就是在PHP代碼編譯期間,注入ticks指令,可以執(zhí)行相應(yīng)的函數(shù),我們可以在這些函數(shù)中檢測(cè)處理協(xié)程的時(shí)間,達(dá)到搶占式的效果,但是這里有一個(gè)問(wèn)題,PHPdeclare(ticks=N)語(yǔ)法,只對(duì)當(dāng)前腳本范圍有效,也就是說(shuō)項(xiàng)目稍微大點(diǎn),require或者include進(jìn)來(lái)的腳本,并不會(huì)自動(dòng)注入ticks指令,這樣Swoole開發(fā)者幾乎是無(wú)法接受的。我們也試圖給PHP官方提一個(gè)PR,可以在擴(kuò)展層設(shè)置一個(gè)全局默認(rèn)的ticks,但是官方不愿意采納我們的提交,因?yàn)楣俜接X(jué)得這個(gè)功能對(duì)性能損耗比較大,而且有可能在PHP8移除這個(gè)功能。其實(shí)經(jīng)過(guò)實(shí)測(cè)這個(gè)性能損耗并不大,而且我們已經(jīng)在生產(chǎn)環(huán)境驗(yàn)證,并取得了顯著的效果,即可以讓出某些CPU密集的邏輯部分,使得服務(wù)整個(gè)相應(yīng)時(shí)間更加均衡。

下圖是我們生產(chǎn)環(huán)境一個(gè)RPC接口的調(diào)用端統(tǒng)計(jì)數(shù)據(jù)對(duì)比,客戶端等待超時(shí)時(shí)間為2s,超時(shí)則統(tǒng)計(jì)為錯(cuò)誤。


左邊一側(cè)是沒(méi)有搶占式調(diào)度,右側(cè)是開了搶占式調(diào)度,可以發(fā)現(xiàn),左側(cè)總是會(huì)有偶爾超時(shí)情況,而經(jīng)過(guò)優(yōu)化之后,沒(méi)有一個(gè)超時(shí)的請(qǐng)求,請(qǐng)求響應(yīng)時(shí)間非常平滑,提升了服務(wù)的穩(wěn)定性。


可以從上圖看出,由于搶占式調(diào)度的加入,去除了請(qǐng)求耗時(shí)高的毛刺,使得平均請(qǐng)求時(shí)間變得更加平滑,穩(wěn)定。

想要做搶占式調(diào)度,對(duì)于PHP來(lái)說(shuō),有兩個(gè)途徑

  • 單線程的PHP的執(zhí)行流,通過(guò)執(zhí)行指令做文章,可以在PHP執(zhí)行流程中注入邏輯,以檢查執(zhí)行時(shí)間,再加上Swoole的協(xié)程能力,可以在不同的協(xié)程中切換,以達(dá)到搶占CPU的目的。
  • 考慮開線程,負(fù)責(zé)檢查當(dāng)前執(zhí)行協(xié)程執(zhí)行時(shí)間。

經(jīng)過(guò)以上辦法的嘗試,注入指令的路數(shù)基本是無(wú)法得到官方的支持,我們只能另謀出路,多開一個(gè)線程,只負(fù)責(zé)檢查當(dāng)前協(xié)程。具體的做法是,利用PHP-7.1.0引入的VM interrupt機(jī)制,默認(rèn)每隔5ms檢查一下當(dāng)前協(xié)程是否達(dá)到最大執(zhí)行時(shí)間,默認(rèn)為10ms,如果超過(guò),則讓出當(dāng)前協(xié)程,達(dá)到被其他協(xié)程搶占的目的。

示例代碼

需要Swoole 4.4或更高版本
?php
Co::set(['enable_preemptive_scheduler' => 1]);
$start = microtime(1);
echo "start\n";
$flag = 1;

go(function () use ($flag) {
 echo "coro 1 start to loop\n";
 $i = 0;
 for (;;) {
  if (!$flag) {
   break;
  }
  $i++;
 }
 echo "coro 1 can exit\n";
});
 
$end = microtime(1);
$msec = ($end - $start) * 1000;
echo "use time $msec\n";
go(function () use ($flag) {
 echo "coro 2 set flag = false\n";
 $flag = false;
});
echo "end\n";

執(zhí)行結(jié)果

start
coro 1 start to loop
use time 11.121988296509
coro 2 set flag = false
end
coro 1 can exit

可以發(fā)現(xiàn),代碼邏輯可以從第一個(gè)協(xié)程的死循環(huán)中自動(dòng)yield出來(lái),執(zhí)行第二個(gè)協(xié)程,如果沒(méi)有這個(gè)特性,第二個(gè)協(xié)程永遠(yuǎn)不會(huì)被執(zhí)行,導(dǎo)致被餓死。而這樣做,第二個(gè)協(xié)程可以順利被執(zhí)行,最后執(zhí)行結(jié)束后,第一個(gè)協(xié)程也會(huì)接著繼續(xù)往下執(zhí)行。達(dá)到我們的第二個(gè)協(xié)程主動(dòng)搶占第一個(gè)協(xié)程CPU的效果。

這個(gè)特性在生產(chǎn)環(huán)境非常有用,尤其是對(duì)于實(shí)時(shí)系統(tǒng)或者響應(yīng)時(shí)間比較敏感的場(chǎng)景。

最后

感謝大家對(duì) Swoole 的長(zhǎng)期支持和關(guān)注。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • 在Laravel5.6中使用Swoole的協(xié)程數(shù)據(jù)庫(kù)查詢
  • 關(guān)于Curl在Swoole協(xié)程中的解決方案詳析

標(biāo)簽:江蘇 棗莊 廣元 萍鄉(xiāng) 衡水 衢州 大理 蚌埠

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Swoole4.4協(xié)程搶占式調(diào)度器詳解》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    建瓯市| 鹤峰县| 孝义市| 石狮市| 年辖:市辖区| 翼城县| 太谷县| 大城县| 古丈县| 台安县| 体育| 临澧县| 盐山县| 北流市| 高邮市| 马龙县| 灌南县| 小金县| 汉中市| 丰原市| 泰来县| 无为县| 汉源县| 余姚市| 龙山县| 禹城市| 永福县| 广汉市| 会昌县| 林西县| 金坛市| 济宁市| 洪洞县| 乐昌市| 灵璧县| 黄大仙区| 蒙山县| 普兰店市| 自贡市| 桃园县| 梨树县|