Swoole 協程中 sleep 為什么會導致死鎖?

Swoole 協程中 sleep 為什么會導致死鎖?

swoole 協程 sleep() 函數導致死鎖的深入分析

本文探討 Swoole 協程中 sleep() 函數可能導致死鎖的問題,并通過代碼示例詳細分析原因及解決方案。

問題重現

在 Swoole 4.8.9 版本中,運行以下代碼會引發“[fatal Error]: all coroutines (count: 1) are asleep – deadlock!”錯誤:

<?php use SwooleProcess;  class Deadlock {     public function startProcess()     {         $t = new SwooleProcess(function () {             swoole_async_set(['enable_coroutine' => true]);             go(function (){                 while (true) {                     SwooleCoroutineSystem::sleep(1);                     var_dump('dd');                 }             });         });         $t->start();     } }  $proc = new Process(function () {     swoole_async_set(['enable_coroutine' => false]);     $cls = new Deadlock();     SwooleTimer::after(1000, function () use ($cls) {         $cls->startProcess(); // 延遲一秒后啟動子進程     }); }); $proc->start();

根源剖析

代碼中,Deadlock 類啟動一個子進程,并在子進程中啟用協程,該協程無限循環調用 SwooleCoroutineSystem::sleep(1)。關鍵在于父進程的配置和調用時機:

  1. 父進程禁用協程: swoole_async_set([‘enable_coroutine’ => false]) 在父進程中禁用了協程。
  2. 延遲調用: 父進程使用 SwooleTimer::after(1000, …) 延遲一秒后,才調用 startProcess() 啟動子進程中的協程。

由于父進程未啟用協程,當子進程中的協程進入 sleep() 狀態后,系統中沒有其他可執行的協程,導致所有協程休眠,從而引發死鎖。

解決方案

為了避免死鎖,需要保持父進程和子進程的協程環境一致性。以下兩種方法可以解決問題:

方法一:父進程啟用協程

在父進程中啟用協程,允許父進程在子進程協程休眠時繼續執行其他任務:

<?php // ... (Deadlock 類代碼不變) ...  $proc = new Process(function () {     swoole_async_set(['enable_coroutine' => true]); // 啟用父進程協程     $cls = new Deadlock();     SwooleTimer::after(1000, function () use ($cls) {         $cls->startProcess();     }); }); $proc->start();

方法二:子進程禁用協程 (不推薦)

在子進程中禁用協程,雖然避免了死鎖,但失去了協程帶來的并發優勢:

<?php use SwooleProcess;  class Deadlock {     public function startProcess()     {         $t = new SwooleProcess(function () {             // swoole_async_set(['enable_coroutine' => true]); // 禁用子進程協程             for (; ;) {                 sleep(1); // 使用同步sleep                 var_dump('dd');             }         });         $t->start();     } }  // ... (父進程代碼不變) ...

推薦使用方法一,即在父進程中啟用協程,以充分利用 Swoole 協程的優勢。 方法二雖然解決了死鎖,但失去了協程的并發性,降低了程序效率。

通過以上分析和修改,我們可以有效避免 Swoole 協程 sleep() 函數導致的死鎖問題,確保程序的穩定性和高效性。

? 版權聲明
THE END
喜歡就支持一下吧
點贊10 分享