W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Hack提供了一種稱(chēng)為Async的功能,為您的程序提供了協(xié)作多任務(wù)的好處。它允許使用Async基礎(chǔ)架構(gòu)的代碼隱藏輸入/輸出(I / O)延遲和數(shù)據(jù)提取。因此,如果您的代碼具有涉及某種等待(例如,網(wǎng)絡(luò)訪問(wèn),等待數(shù)據(jù)庫(kù)查詢(xún))的操作,則async將您的程序停止運(yùn)行的停機(jī)時(shí)間最小化,因?yàn)槌绦驅(qū)?zhí)行其他操作可能會(huì)在其他地方進(jìn)一步的I / O。
Async 不是多線程 - HHVM仍然在一個(gè)主要請(qǐng)求線程中執(zhí)行所有的PHP / Hack代碼 - 但是其他操作(例如MySQL查詢(xún))現(xiàn)在可以執(zhí)行,而不需要在該代碼中使用的時(shí)間。
想象一下,你有一個(gè)頁(yè)面包含兩個(gè)組件; 一個(gè)在MySQL中存儲(chǔ)數(shù)據(jù),另一個(gè)通過(guò)cURL從API獲取數(shù)據(jù),兩個(gè)緩存都導(dǎo)致Memcached。依賴(lài)關(guān)系可以這樣建模:
這樣的代碼結(jié)構(gòu)從Async中獲得最大的收益。
如果(像大多數(shù)PHP代碼)你不使用Async編程,每一步將一個(gè)接一個(gè)執(zhí)行:
所有PHP / Hack代碼在主請(qǐng)求線程中執(zhí)行,但是I / O不阻止它,并且多個(gè)I / O或其他Async任務(wù)可以同時(shí)執(zhí)行。如果您的代碼構(gòu)造為依賴(lài)樹(shù)并使用AsyncI / O,這將導(dǎo)致代碼的各個(gè)部分透明地交錯(cuò)而不是彼此阻塞:
重要的是,您的代碼執(zhí)行的順序是不能保證的 - 例如,如果組件A的cURL請(qǐng)求速度較慢,則執(zhí)行相同的代碼可能會(huì)更像這樣:
以這種方式重新排序不同的任務(wù)指令,可以隱藏I / O 延遲。因此,當(dāng)一個(gè)任務(wù)當(dāng)前處于I / O指令(例如,等待數(shù)據(jù))時(shí),另一個(gè)任務(wù)的指令,希望能夠減少延遲,可以在此期間執(zhí)行。
兩個(gè)最重要的限制是:
例如,給出這個(gè)代碼:
<?hh
namespace Hack\UserDocumentation\Async\Intro\Examples\Limtations;
async function do_cpu_work(): Awaitable<void> {
print("Start CPU work\n");
$a = 0;
$b = 1;
$list = [$a, $b];
for ($i = 0; $i < 1000; ++$i) {
$c = $a + $b;
$list[] = $c;
$a = $b;
$b = $c;
}
print("End CPU work\n");
}
async function do_sleep(): Awaitable<void> {
print("Start sleep\n");
sleep(1);
print("End sleep\n");
}
async function main(): Awaitable<void> {
print("Start of main()\n");
await \HH\Asio\v([
do_cpu_work(),
do_sleep(),
]);
print("End of main()\n");
}
\HH\Asio\join(main());
新用戶(hù)經(jīng)常認(rèn)為與多線程Async,所以期望do_cpu_work()并且do_sleep()并行執(zhí)行 - 但是,這不會(huì)發(fā)生,因?yàn)闆](méi)有可以移動(dòng)到后臺(tái)的操作:
在沒(méi)有Async的情況下使兩個(gè)cURL請(qǐng)求的一種天真的方式可能如下所示:
<?hh
namespace Hack\UserDocumentation\Async\Intro\Examples\NonAsyncCurl;
function curl_A(): mixed {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.com/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
return curl_exec($ch);
}
function curl_B(): mixed {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.net/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
return curl_exec($ch);
}
function main(): void {
$start = microtime(true);
$a = curl_A();
$b = curl_B();
$end = microtime(true);
echo "Total time taken: " . strval($end - $start) . " seconds" . PHP_EOL;
}
main();
Output
Total time taken: 1.050155878067 seconds
在上面的示例中,對(duì)curl_exec()
in 的調(diào)用curl_A()
阻止了任何其他處理。因此,即使curl_B()
是獨(dú)立的電話(huà)curl_A()
,curl_A()
在開(kāi)始執(zhí)行之前也必須等待完成:
幸運(yùn)的是,HHVM提供了一個(gè)Async版本curl_exec()
:
<?hh
namespace Hack\UserDocumentation\Async\Intro\Examples\Curl;
async function curl_A(): Awaitable<string> {
$x = await \HH\Asio\curl_exec("http://example.com/");
return $x;
}
async function curl_B(): Awaitable<string> {
$y = await \HH\Asio\curl_exec("http://example.net/");
return $y;
}
async function async_curl(): Awaitable<void> {
$start = microtime(true);
list($a, $b) = await \HH\Asio\v(array(curl_A(), curl_B()));
$end = microtime(true);
echo "Total time taken: " . strval($end - $start) . " seconds" . PHP_EOL;
}
\HH\Asio\join(async_curl());
Output
Total time taken: 0.74790596961975 seconds
Async版本curl_exec()
允許調(diào)度程序在等待cURL的響應(yīng)時(shí)運(yùn)行其他代碼。最可能的行為是,當(dāng)我們還在等待調(diào)用時(shí)curl_B()
,調(diào)度程序?qū)⑦x擇調(diào)用它,這反過(guò)來(lái)又會(huì)啟動(dòng)另一個(gè)Async
curl_exec()
。由于HTTP請(qǐng)求通常較慢,因此主線程將處于空閑狀態(tài),直到其中一個(gè)請(qǐng)求完成:
這個(gè)執(zhí)行令是最有可能的,但不是保證; 例如,如果curl_B()請(qǐng)求比curl_A()HTTP請(qǐng)求快得多,curl_B()可以在完成之前curl_A()完成。
Async加速此示例的數(shù)量可能會(huì)有很大差異(例如,根據(jù)網(wǎng)絡(luò)條件和DNS緩存),但可能很重要:
Async
Total time taken: 0.74790596961975 seconds
Non-Async
Total time taken: 1.050155878067 seconds
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: