摘要:協(xié)程協(xié)程就是用戶態(tài)的線程要理解是什么是用戶態(tài)的線程,必然就要先理解什么是內(nèi)核態(tài)的線程。記住,不是協(xié)程,而是協(xié)程需要借助的特性來(lái)實(shí)現(xiàn)。
協(xié)程
“協(xié)程”就是用戶態(tài)的線程關(guān)于“用戶態(tài)線程”,我們用個(gè)小例子來(lái)加深理解要理解是什么是“用戶態(tài)的線程”,必然就要先理解什么是“內(nèi)核態(tài)的線程”。 內(nèi)核態(tài)的線程是由操作系統(tǒng)來(lái)進(jìn)行調(diào)度的,在切換線程上下文時(shí),要先保存上一個(gè)線程的上下文,然后執(zhí)行下一個(gè)線程,當(dāng)條件滿足時(shí),切換回上一個(gè)線程,并恢復(fù)上下文。 協(xié)程也是如此,只不過(guò),用戶態(tài)的線程不是由操作系統(tǒng)來(lái)調(diào)度的,而是由程序員來(lái)調(diào)度的,是在用戶態(tài)的 -- 摘自鏈接描述
我們有兩個(gè)函數(shù) task1,task2,我們來(lái)手動(dòng)調(diào)度它們的執(zhí)行順序,比如在task1執(zhí)行一半的時(shí)候去執(zhí)行task2,兩個(gè)或者多個(gè)函數(shù)之間交替執(zhí)行(這就是協(xié)程的概念)。
我們來(lái)個(gè)正常的函數(shù)調(diào)用方式:
可想而知,以上的輸出肯定是:
task1函數(shù) 執(zhí)行第1 task1函數(shù) 執(zhí)行第2 task2函數(shù) 執(zhí)行第1 task2函數(shù) 執(zhí)行第2但是我想在程序輸出task1函數(shù) 執(zhí)行1之后就輸出task2函數(shù) 執(zhí)行1怎么辦?
這個(gè)時(shí)候 yield 就派上用場(chǎng)了,PHP里的協(xié)程是需要借助 yield 來(lái)完成的。記住,yield 不是協(xié)程,而是協(xié)程需要借助 yield 的特性來(lái)實(shí)現(xiàn)。
current(); $task2->current();以上輸出:
task1函數(shù) 執(zhí)行1 task2函數(shù) 執(zhí)行1很好,以上結(jié)果達(dá)到了我們的預(yù)期。但是怎么讓函數(shù)里的代碼往下執(zhí)行呢?
調(diào)用生成器的next方法:
$task1->next(); $task2->next();最后你將看到的輸出結(jié)果是兩個(gè)函數(shù)交替執(zhí)行輸出的:
task1函數(shù) 執(zhí)行1 task2函數(shù) 執(zhí)行1 task1函數(shù) 執(zhí)行2 task2函數(shù) 執(zhí)行2小段總結(jié)以上的代碼實(shí)現(xiàn)可以抽象出兩個(gè)概念,任務(wù)和調(diào)度,任務(wù)就是task函數(shù),調(diào)度就是我們?cè)趺慈フ{(diào)用這些task函數(shù)
調(diào)度器和任務(wù)生成器上一個(gè)小段總結(jié)里有兩個(gè)概念叫任務(wù)和調(diào)度,我們簡(jiǎn)單的封裝個(gè)任務(wù)生成器和調(diào)度器
// 任務(wù)生成器 $createTask = (function () { $tasks = []; return function ($callback) use (&$tasks) { $task = [ "task" => $callback(), "id" => count($tasks) + 1, ]; array_push($tasks, $task); return $task; }; })(); // 調(diào)度器 function schedule($tasks) { $first = []; while (!empty($tasks)) { $task = array_shift($tasks); if (!array_key_exists($task["id"], $first)) { $first[$task["id"]] = true; $task["task"]->current(); } else { $task["task"]->next(); } if (!$task["task"]->valid()) { unset($tasks[$k]); } else { array_push($tasks, $task); } } }使用
$tasks = [ $createTask(function () { echo "任務(wù)1 執(zhí)行第1次 "; yield; echo "任務(wù)1 執(zhí)行第2次 "; }), $createTask(function () { echo "任務(wù)2 執(zhí)行第1次 "; yield; echo "任務(wù)2 執(zhí)行第2次 "; }) ]; schedule($tasks);輸出結(jié)果:
任務(wù)1 執(zhí)行第1次 任務(wù)2 執(zhí)行第1次 任務(wù)1 執(zhí)行第2次 任務(wù)2 執(zhí)行第2次可以從結(jié)果看出,調(diào)度器已經(jīng)實(shí)現(xiàn)了多個(gè)任務(wù)之間進(jìn)行協(xié)作。
網(wǎng)絡(luò)請(qǐng)求現(xiàn)在有個(gè)需求!就是任務(wù)在遇到網(wǎng)絡(luò)請(qǐng)求的時(shí)候,我們無(wú)需等待網(wǎng)絡(luò)請(qǐng)求的響應(yīng)結(jié)果,而是遇到網(wǎng)絡(luò)請(qǐng)求的時(shí)候,把這個(gè)任務(wù)掛起,然后去執(zhí)行其它任務(wù),等網(wǎng)絡(luò)請(qǐng)求收到響應(yīng)結(jié)果了再通知我們處理這時(shí)候需要我們用到非阻塞IO調(diào)用相關(guān)技術(shù),涉及到系統(tǒng)內(nèi)核層面,想了解可以點(diǎn)擊鏈接描述
在PHP里我們需要安裝個(gè)擴(kuò)展eio,大家自行安裝
pecl install eio編碼:
$tasks = [ $createTask(function () { echo "任務(wù)1 執(zhí)行第1次 "; yield; echo "任務(wù)1 執(zhí)行第2次 "; }), $createTask(function () { echo "任務(wù)2 執(zhí)行第1次 "; eio_custom(function () { return file_get_contents("https://segmentfault.com/"); }, EIO_PRI_DEFAULT, function ($data, $ret) { echo "請(qǐng)求完成 "; }); yield; echo "任務(wù)2 執(zhí)行第2次 "; }) ]; schedule($tasks); eio_event_loop();在任務(wù)2 執(zhí)行第1次的時(shí)候,遇到網(wǎng)絡(luò)請(qǐng)求,我們把請(qǐng)求任務(wù)交給系統(tǒng)內(nèi)核,然后切換到其它任務(wù)去,等請(qǐng)求任務(wù)完成后回調(diào)我們傳入的函數(shù)。
輸出結(jié)果:
任務(wù)1 執(zhí)行第1次 任務(wù)2 執(zhí)行第1次 任務(wù)1 執(zhí)行第2次 任務(wù)2 執(zhí)行第2次 任務(wù)2 執(zhí)行第1次的請(qǐng)求完成完!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29283.html
摘要:本文先回顧生成器,然后過(guò)渡到協(xié)程編程。其作用主要體現(xiàn)在三個(gè)方面數(shù)據(jù)生成生產(chǎn)者,通過(guò)返回?cái)?shù)據(jù)數(shù)據(jù)消費(fèi)消費(fèi)者,消費(fèi)傳來(lái)的數(shù)據(jù)實(shí)現(xiàn)協(xié)程。解決回調(diào)地獄的方式主要有兩種和協(xié)程。重點(diǎn)應(yīng)當(dāng)關(guān)注控制權(quán)轉(zhuǎn)讓的時(shí)機(jī),以及協(xié)程的運(yùn)作方式。 轉(zhuǎn)載請(qǐng)注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎(chǔ) web請(qǐng)求 cookie web響應(yīng) sess...
摘要:為語(yǔ)言提供了強(qiáng)大的協(xié)程編程模式。提供的協(xié)程語(yǔ)法借鑒自,在此向開(kāi)發(fā)組致敬協(xié)程可以與很好地互補(bǔ)。并發(fā)執(zhí)行使用創(chuàng)建協(xié)程,可以讓和兩個(gè)函數(shù)變成并發(fā)執(zhí)行。協(xié)程需要拿到請(qǐng)求的結(jié)果。 Swoole4為PHP語(yǔ)言提供了強(qiáng)大的CSP協(xié)程編程模式。底層提供了3個(gè)關(guān)鍵詞,可以方便地實(shí)現(xiàn)各類功能。 Swoole4提供的PHP協(xié)程語(yǔ)法借鑒自Golang,在此向GO開(kāi)發(fā)組致敬 PHP+Swoole協(xié)程可以與...
摘要:協(xié)程完全有用戶態(tài)程序控制,所以也被成為用戶態(tài)的線程。目前支持協(xié)程的語(yǔ)言有很多,例如等。協(xié)程之旅前篇結(jié)束,下一篇文章我們將深入分析原生協(xié)程部分的實(shí)現(xiàn)。 寫(xiě)在最前 ??Swoole協(xié)程經(jīng)歷了幾個(gè)里程碑,我們需要在前進(jìn)的道路上不斷總結(jié)與回顧自己的發(fā)展歷程,正所謂溫故而知新,本系列文章將分為協(xié)程之旅前、中、后三篇。 前篇主要介紹協(xié)程的概念和Swoole幾個(gè)版本協(xié)程實(shí)現(xiàn)的主要方案技術(shù); 中篇主...
摘要:搶占式調(diào)度我們?cè)诮衲昴瓿蹙陀?jì)劃實(shí)現(xiàn)的搶占式調(diào)度,以滿足實(shí)現(xiàn)有些場(chǎng)景下的不均衡調(diào)度帶來(lái)的問(wèn)題??紤]開(kāi)線程,負(fù)責(zé)檢查當(dāng)前執(zhí)行協(xié)程執(zhí)行時(shí)間。達(dá)到我們的第二個(gè)協(xié)程主動(dòng)搶占第一個(gè)協(xié)程的效果。 前言 Swoole內(nèi)核團(tuán)隊(duì)開(kāi)設(shè)的專欄,會(huì)逐漸投入精力寫(xiě)文章介紹Swoole的開(kāi)發(fā)歷程,實(shí)現(xiàn)原理,應(yīng)用實(shí)踐等,大家可以更好的交流,共同學(xué)習(xí),建設(shè)PHP生態(tài)。 協(xié)程調(diào)度 去年Swoole推出了4.0版本后,完整...
摘要:如果僅依靠程序自動(dòng)交出控制的話,那么一些惡意程序?qū)?huì)很容易占用全部時(shí)間而不與其他任務(wù)共享。多個(gè)操作可以在重疊的時(shí)間段內(nèi)進(jìn)行。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器,你可以根據(jù)下面目錄翻閱 PHP下的異步嘗試一:初識(shí)生成器 PHP下的異步嘗試二:初識(shí)協(xié)程 PHP下的異步嘗試三:協(xié)程的PHP版thunkify自動(dòng)執(zhí)行器 PHP下的異步嘗試四:PHP版的Promise ...
摘要:線程擁有自己獨(dú)立的棧和共享的堆,共享堆,不共享?xiàng)#€程亦由操作系統(tǒng)調(diào)度標(biāo)準(zhǔn)線程是的。以及鳥(niǎo)哥翻譯的這篇詳細(xì)文檔我就以他實(shí)現(xiàn)的協(xié)程多任務(wù)調(diào)度為基礎(chǔ)做一下例子說(shuō)明并說(shuō)一下關(guān)于我在阻塞方面所做的一些思考。 進(jìn)程、線程、協(xié)程 關(guān)于進(jìn)程、線程、協(xié)程,有非常詳細(xì)和豐富的博客或者學(xué)習(xí)資源,我不在此做贅述,我大致在此介紹一下這幾個(gè)東西。 進(jìn)程擁有自己獨(dú)立的堆和棧,既不共享堆,亦不共享?xiàng)?,進(jìn)程由操作系...
閱讀 1052·2021-11-18 13:23
閱讀 758·2021-11-08 13:16
閱讀 871·2021-10-11 10:58
閱讀 3520·2021-09-22 15:26
閱讀 1749·2021-09-08 10:42
閱讀 1827·2021-09-04 16:45
閱讀 1745·2019-08-30 15:54
閱讀 2576·2019-08-30 13:45