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