php exec卡死 - 一個(gè)令人頭疼的問(wèn)題
如果你有接觸php exec函數(shù)的經(jīng)驗(yàn),你很有可能會(huì)遇到這個(gè)問(wèn)題:執(zhí)行exec命令時(shí)會(huì)卡住整個(gè)程序。在處理大數(shù)據(jù)時(shí),這個(gè)問(wèn)題會(huì)變得更加嚴(yán)重,導(dǎo)致程序崩潰。下面我們來(lái)詳細(xì)探究這個(gè)問(wèn)題。
exec的基本用法
$command = "ls -l"; exec($command, $output, $return_var); echo implode("\n", $output);
這里我們定義了一個(gè)基礎(chǔ)命令,并將其發(fā)送到操作系統(tǒng)。exec函數(shù)返回的結(jié)果包含了系統(tǒng)所有的輸出,并可以通過(guò)第二個(gè)參數(shù)$output獲取。最后的$result就是系統(tǒng)返回的狀態(tài)碼。
關(guān)于卡死的問(wèn)題
下面我們考慮一種情況:用php執(zhí)行一個(gè)命令,該命令執(zhí)行時(shí)間很長(zhǎng)或不會(huì)快速完成時(shí),exec函數(shù)就會(huì)被卡住,程序停止響應(yīng)。這就是卡死的問(wèn)題。具體來(lái)說(shuō),php嘗試讀取系統(tǒng)的輸出時(shí)會(huì)被阻塞,因?yàn)檩敵霰黄渌M(jìn)程所控制。
假設(shè)我們有一個(gè)解析大型csv文件的程序。代碼如下:
$command = "awk 'BEGIN { FS = \",\" } ; {print $1}' /path/to/big/file.csv"; exec($command, $output, $return_var); echo implode("\n", $output);
這段代碼會(huì)將csv文件中的第一列數(shù)據(jù)提取出來(lái)。然而,如果csv文件很大而awk命令處理時(shí)間較長(zhǎng)時(shí),該函數(shù)會(huì)卡住程序,導(dǎo)致程序無(wú)法完成任務(wù)。
一種常見(jiàn)的解決辦法是使用多線程、多進(jìn)程而不是使用exec,因?yàn)槭褂枚嗑€程可以在阻塞的時(shí)候繼續(xù)處理它的它任務(wù),而多進(jìn)程也可以避免這個(gè)問(wèn)題,因?yàn)槊總€(gè)進(jìn)程都運(yùn)行在其自己的內(nèi)存空間中,不會(huì)受到其他進(jìn)程的影響。
除此之外,可以使用pcntl_fork或posix_spawn代替exec。因?yàn)檫@兩個(gè)方法可以在后臺(tái)啟動(dòng)一個(gè)進(jìn)程,避免阻塞。比如:
$command = "awk 'BEGIN { FS = \",\" } ; {print $1}' /path/to/big/file.csv"; $pid = pcntl_fork(); if ($pid === -1) { die('could not fork'); } else if ($pid) { posix_setpgid($pid, $pid); $status = null; pcntl_waitpid($pid, $status); } else { exec($command); exit(0); }
這里,我們使用pcntl_fork來(lái)在子進(jìn)程中執(zhí)行awk命令。父進(jìn)程在子進(jìn)程結(jié)束后,等待子進(jìn)程完成并接收到狀態(tài)碼。
總結(jié)
php exec函數(shù)在處理長(zhǎng)時(shí)間運(yùn)行的命令時(shí)可能會(huì)被卡住。我們可以使用其他方法來(lái)代替exec函數(shù),如多線程、多進(jìn)程等。能解決這個(gè)問(wèn)題。