PHP 本身不支援真正的多線程(需安裝 pthreads 擴展),但在 Web 環境下可透過「偽線程」模擬並發效果:利用 HTTP 請求非阻塞特性,或使用 cURL 多工處理實現真正的並發 I/O。
class Thread
{
private $hooks = array();
private $args = array();
public function addThread($func)
{
$args = array_slice(func_get_args(), 1);
$this->hooks[] = $func;
$this->args[] = $args;
return true;
}
public function runThread()
{
// 子執行緒進入點:透過 flag 參數識別執行哪個任務
if (isset($_GET['flag'])) {
$flag = intval($_GET['flag']);
}
if ($flag !== null || $flag === 0) {
// 子執行緒:執行指定任務
call_user_func_array($this->hooks[$flag], $this->args[$flag]);
} else {
// 主執行緒:發起非阻塞 HTTP 請求觸發子執行緒
for ($i = 0, $size = count($this->hooks); $i < $size; $i++) {
$fp = fsockopen($_SERVER['HTTP_HOST'], $_SERVER['SERVER_PORT']);
if ($fp) {
$out = "GET {$_SERVER['PHP_SELF']}?flag=$i HTTP/1.1\r\n";
$out .= "Host: {$_SERVER['HTTP_HOST']}\r\n";
$out .= "Connection: Close\r\n\r\n";
fputs($fp, $out);
fclose($fp);
}
}
}
}
}
$thread = new Thread();
$thread->addThread('action_log', 'info1');
$thread->addThread('action_log', 'info2');
$thread->addThread('action_log', 'info3');
$thread->runThread();
function action_log($info) {
$log = 'log/' . microtime() . '.log';
$txt = $info . "\r\n\r\n" . 'Set in ' . date('H:i:s', time()) . (double)microtime() . "\r\n";
$fp = fopen($log, 'w');
fwrite($fp, $txt);
fclose($fp);
}
class CurlMulti
{
private $urlList = array();
private $curlOptions = array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_HEADER => 0,
CURLOPT_NOBODY => 0,
CURLOPT_FOLLOWLOCATION => 0,
CURLOPT_TIMEOUT => 6,
);
public function __construct($seconds = 30)
{
set_time_limit($seconds);
}
public function setUrlList(array $list)
{
$this->urlList = $list;
}
public function setOpt(array $options)
{
$this->curlOptions = $options + $this->curlOptions;
}
public function execute()
{
$mh = curl_multi_init();
$conn = array();
// 初始化所有連線
foreach ($this->urlList as $i => $url) {
$conn[$i] = curl_init($url);
foreach ($this->curlOptions as $key => $val) {
curl_setopt($conn[$i], constant($key), $val);
}
curl_multi_add_handle($mh, $conn[$i]);
}
// 並發執行
$active = false;
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
// 收集結果
$results = array();
foreach ($this->urlList as $i => $url) {
$results[$i] = curl_multi_getcontent($conn[$i]);
curl_close($conn[$i]);
curl_multi_remove_handle($mh, $conn[$i]);
}
curl_multi_close($mh);
return $results;
}
}
$curlMulti = new CurlMulti();
$curlMulti->setUrlList(array(
'https://example.com/img1.jpg',
'https://example.com/img2.jpg',
'https://example.com/img3.jpg',
));
$results = $curlMulti->execute();
$i = 1;
foreach ($results as $content) {
$filename = $i . '.jpg';
$fp = fopen($filename, 'wb');
fwrite($fp, $content);
fclose($fp);
$i++;
}
// 僅限 CLI 環境,需安裝 pthreads 擴展
class DownloadThread extends Thread
{
public $url;
public $savePath;
public $result;
public function run()
{
$this->result = file_put_contents($this->savePath, file_get_contents($this->url));
}
}
$urls = array('https://example.com/1.jpg', 'https://example.com/2.jpg');
$threads = array();
foreach ($urls as $i => $url) {
$thread = new DownloadThread();
$thread->url = $url;
$thread->savePath = "downloads/{$i}.jpg";
$thread->start();
$threads[] = $thread;
}
foreach ($threads as $thread) {
$thread->join();
echo "Downloaded: {$thread->savePath} ({$thread->result} bytes)\n";
}
// Swoole 4.0+ 協程風格
Co\run(function() {
$urls = array('https://example.com/1.jpg', 'https://example.com/2.jpg');
$channel = new Chan(count($urls));
foreach ($urls as $i => $url) {
go(function() use ($url, $i, $channel) {
$content = Co::get($url); // 協程非阻塞 HTTP
file_put_contents("downloads/{$i}.jpg", $content);
$channel->push($i);
});
}
for ($i = 0; $i < count($urls); $i++) {
$channel->pop();
}
echo "All downloaded\n";
});
| 方案 | 環境需求 | 並發類型 | 效能 | 複雜度 | 適用場景 |
|---|---|---|---|---|---|
| 偽線程 | 標準 PHP | 進程級 | 低 | 簡單 | 簡單異步任務 |
| cURL 多工 | 標準 PHP + cURL | I/O 多工 | 高 | 中等 | 並發 HTTP 請求、爬蟲、下載 |
| pthreads | CLI + pthreads 擴展 | 真多線程 | 高 | 高 | CPU 密集型、長時間運行 CLI |
| Swoole | Swoole 擴展 | 協程 | 極高 | 中等 | 高併發服務、WebSocket、微服務 |
選擇合適的並發方案,能讓 PHP 突破單線程限制,高效處理 I/O 密集型任務。