在理解進程和線程概念以前首選要對併發有必定的感性認識,若是服務器同一時間內只能服務於一個客戶端,其餘客戶端都再那裏傻等的話,可見其性能的低下估計會被客戶罵出翔來,所以併發編程應運而生,併發是網絡編程中必須考慮的問題。實現併發的方式有多種:好比多進程、多線程、IO多路複用。面試
進程是資源(CPU、內存等)分配的基本單位,它是程序執行時的一個實例。程序運行時系統就會建立一個進程,併爲它分配資源,而後把該進程放入進程就緒隊列,進程調度器選中它的時候就會爲它分配CPU時間,程序開始真正運行。編程
Linux系統函數fork()
能夠在父進程中建立一個子進程,這樣的話,在一個進程接到來自客戶端新的請求時就能夠複製出一個子進程讓其來處理,父進程只需負責監控請求的到來,而後建立子進程讓其去處理,這樣就能作到併發處理。服務器
# -*- coding:utf-8 -*- import os print('當前進程:%s 啓動中 ....' % os.getpid()) pid = os.fork() if pid == 0: print('子進程:%s,父進程是:%s' % (os.getpid(), os.getppid())) else: print('進程:%s 建立了子進程:%s' % (os.getpid(),pid ))
輸出結果:網絡
當前進程:27223 啓動中 .... 進程:27223 建立了子進程:27224 子進程:27224,父進程是:27223
fork函數會返回兩次結果,由於操做系統會把當前進程的數據複製一遍,而後程序就分兩個進程繼續運行後面的代碼,fork分別在父進程和子進程中返回,在子進程返回的值pid永遠是0,在父進程返回的是子進程的進程id。多線程
線程是程序執行時的最小單位,它是進程的一個執行流,是CPU調度和分派的基本單位,一個進程能夠由不少個線程組成,線程間共享進程的全部資源,每一個線程有本身的堆棧和局部變量。線程由CPU獨立調度執行,在多CPU環境下就容許多個線程同時運行。一樣多線程也能夠實現併發操做,每一個請求分配一個線程來處理。併發
進程是資源分配的最小單位,線程是程序執行的最小單位。less
進程有本身的獨立地址空間,每啓動一個進程,系統就會爲它分配地址空間,創建數據表來維護代碼段、堆棧段和數據段,這種操做很是昂貴。而線程是共享進程中的數據的,使用相同的地址空間,所以CPU切換一個線程的花費遠比進程要小不少,同時建立一個線程的開銷也比進程要小不少。函數
線程之間的通訊更方便,同一進程下的線程共享全局變量、靜態變量等數據,而進程之間的通訊須要以通訊的方式(IPC)進行。不過如何處理好同步與互斥是編寫多線程程序的難點。性能
可是多進程程序更健壯,多線程程序只要有一個線程死掉,整個進程也死掉了,而一個進程死掉並不會對另一個進程形成影響,由於進程有本身獨立的地址空間。ui
老外的原話是這麼說的 —-《Unix網絡編程》:
fork is expensive. Memory is copied from the parent to the child, all descriptors are duplicated in the child, and so on. Current implementations use a technique called copy-on-write, which avoids a copy of the parent’s data space to the child until the child needs its own copy. But, regardless of this optimization, fork is expensive.
IPC is required to pass information between the parent and child after the fork. Passing information from the parent to the child before the fork is easy, since the child starts with a copy of the parent’s data space and with a copy of all the parent’s descriptors. But, returning information from the child to the parent takes more work.
Threads help with both problems. Threads are sometimes called lightweight processes since a thread is 「lighter weight」 than a process. That is, thread creation can be 10–100 times faster than process creation.
All threads within a process share the same global memory. This makes the sharing of information easy between the threads, but along with this simplicity comes the problem