2014-01-12 29 views
1

在Java Web應用程序中,通常會產生線程來處理Web請求。我指的是應用程序代碼,而不是容器的線程來接受傳入的客戶端連接。
在腳本語言中,例如Perl或Python,我的理解是,使用多處理範例(fork進程)比多線程處理(fork線程)要頻繁得多。
我個人發現分叉進程,而不是Web服務器應用程序代碼中的線程「怪異」和更重。
我正確嗎?在這些框架中的Web處理過程中是否會分叉進程?在腳本化Web應用程序中首選分叉進程(而不是分叉線程)?

+0

「在Java Web應用程序中,通常會產生線程來處理Web請求。」你是認真的嗎?這到底是誰呢? –

+0

@MikeBaranczak:我不是在談論http線程。我正在談論後端操作。通常使用線程或線程池。例子將是一個後臺線程,例如,記錄與當前請求相關的內容(不會阻止它)或在後端發送郵件等。 – Jim

+0

好的,謝謝澄清。分叉和線程之間的選擇取決於操作系統,以及父母和孩子之間需要多少互動。請參閱:http://stackoverflow.com/questions/16354460/forking-vs-threading –

回答

2

Perl線程真的很重(請參閱How do I reduce memory consumption when using many threads in Perl?)。從我讀的Python中的線程受到全局解釋器鎖的阻礙。 Java中的線程似乎更輕量化,但不像Linux中的操作系統線程那麼輕量級。

如果你想在Perl中進行繁重的網絡連接,你不要使用線程,而是使用類似於AnyEvent或POE的基於事件的編程,類似於具有Twisted框架的Python。有幾個基於這些框架的Web服務器。 Java也有NIO框架,甚至在C現代快速Web服務器(如nginx)中使用基於事件的編程,而不是線程或進程。

我不知道任何常見的Web服務器,它分叉處理請求。如果他們完全岔開,他們使用預分叉模型,例如,他們預先派生了大量的工作進程(或者工作線程,如果他們使用線程而不是進程),並且如果有新的請求進入,則由現有工作人員處理。這比僅使用非常簡單的服務器的請求式分支模型花費少得多。具有基於事件的處理的服務器也可能會分叉,但通常僅用於有效使用多個CPU(例如每個CPU一個進程)。

通過預分叉Web服務器,Web應用程序通常根本不分叉,只是使用當前進程。基於事件的Web服務器通常只能在內部和快速處理靜態內容,因爲它們通過FCGI等接口連接到其他過程(通常是預分配)的較慢的動態內容。這節省了資源,因爲對於普通的網頁,大多數請求都是針對靜態內容的。

在Web應用程序中可能仍然存在分叉的原因。這是,如果您需要在後臺執行一些工作(如調整上傳的圖像大小),而頁面已完成並且內容應發送給用戶。但即使在這種情況下,它的規模也要好得多,才能擁有一個專門的進程/線程來完成這項工作,並且只需要完成任務。

至於創建一個線程與一個進程的性能:一個進程的叉是在Unix/Linux(但不是在Windows中)便宜,因爲它簡單地克隆現有的進程結構並標記所有共享內存頁面例如最初的所有頁面)作爲寫入時拷貝。只有當新進程有效時,纔會複製已更改的內存頁面(這是昂貴的部分)。創建線程的代價在編程語言和操作系統之間差別很大,並不需要比創建新進程更快。

+0

如果使用不當,Perl線程真的很重*。流程同樣如此。 – ikegami

+0

在Perl中創建線程和那裏的內存使用情況在其他語言的線程中花費要高得多,因爲整個解釋器包含。所有未明確共享的東西都被克隆。比使用支持線程編譯的Perl支付約15%的性能損失。但是,只要知道這些缺點,線程就可以以這些缺點無關緊要的方式使用(如使用工作池)。 –

+0

@SteffenUllrich:答案中的內容是有用的和內容豐富的,但答案(除了一小部分)與我的問題無關。我的問題是關於處理傳入客戶端連接的線程池(在Java中可以使用阻塞方法或NIO)或基於事件的框架。這個問題僅僅集中在Web應用程序內需要完成的後端任務**,日誌數據在一個單獨的線程比框架客戶端連接線程等 – Jim