2014-10-01 43 views
0

我想讓PHP告訴Apache關閉連接並分別釋放工作線程。原因是我有一個腳本與客戶端請求一起調用,需要一些時間來處理,但不向客戶端返回任何內容,因此保持佔用線程是沒有意義的。目前我正在使用的代碼:如何從PHP關閉Apache線程?

ignore_user_abort(true); 
header('Content-Length: 0'); 
flush(); 
ob_end_flush(); 
header('Connection: Close'); 

由於我從原來的用戶請求發送額外的異步請求到該腳本,Content-Length: 0不會弄亂客戶端請求的響應。

無論如何,當我去監視服務器在做什麼時,我發現有一個工作線程佔用了長時間運行的請求,這正是我想要不發生的事情。我希望腳本在後臺運行而不佔用Apache線程。我怎樣才能做到這一點?

+0

這實際上並不是多線程。您可以使用'pthreads'進行多線程(並不平凡,因爲它通常需要重新編譯PHP),而且我聽說即使在Apache進程中也可以完成。或者使用隊列系統,如Gearman或Resque。 – halfer 2014-10-02 09:59:55

+0

如果你在共享主機,但它可能值得嘗試['pfork'](http://uk3.php.net/manual/en/function.pcntl-fork.php) - 這裏沒有太多的選擇除了'cron'。 – halfer 2014-10-02 10:07:11

回答

2

這聽起來像一個不好的做法和一大堆麻煩,例如,具有併發性和負載平衡。

考慮執行任務隊列:

  1. 客戶想要一個任務隨意添加到隊列中。
  2. 客戶端發送請求到運行PHP代碼的Apache。
  3. PHP解析輸入並構造一個添加到隊列中的任務。
  4. 服務器向客戶端返回空響應。

然後,設置一個守護進程或cron作業,在Apache之外的後臺處理上述隊列。

這使您可以很好地控制什麼時候發生,而不需要這樣的黑客。作爲獎勵,您可以通過控制隊列的處理速度來控制資源使用情況。 (特別適用於與限制流量的外部API交流的情況。)

如果您希望您的隊列是並行的,則沒有什麼能阻止您這麼做 - 考慮設置多個任務池,並且創建時的每個任務都分配給隨機任務池。然後,爲每個任務池設置守護進程實例 - 不需要PHP線程或類似的東西。

+0

這是有道理的,但我不明白我是如何實現我想用隊列和cron來嘗試的。 「長期請求」實際上是一個私人套接字服務器。我需要服務器在請求發送後立即啓動,並且每秒運行一次cronjob絕對不是一個聰明的主意:? – 2014-10-01 13:42:41

+0

這就是守護進程會更好的地方 - 讓持久化的PHP守護進程知道你想打開一個套接字,並打開它。困難的部分是弄清楚如何做互操作性權限監控文本文件不是很漂亮。 – 2014-10-01 14:45:06

+0

如果需要同時打開多個套接字,而不是嘗試使多線程持久守護進程,則可以使用像exec()這樣的命令產生分離的PHP進程。 – 2014-10-01 14:47:12