我們先來(lái)了解什么是進(jìn)程?
程序并不能單獨(dú)運(yùn)行,只有將程序裝載到內(nèi)存中,系統(tǒng)為它分配資源才能運(yùn)行,而這種執(zhí)行的程序就稱(chēng)之為進(jìn)程,
Python 多進(jìn)程開(kāi)發(fā)與多線程開(kāi)發(fā)
。程序和進(jìn)程的區(qū)別就在于:程序是指令的集合,它是進(jìn)程運(yùn)行的靜態(tài)描述文本;進(jìn)程是程序的一次執(zhí)行活動(dòng),屬于動(dòng)態(tài)概念。在多道編程中,我們?cè)试S多個(gè)程序同時(shí)加載到內(nèi)存中,在操作系統(tǒng)的調(diào)度下,可以實(shí)現(xiàn)并發(fā)地執(zhí)行。這是這樣的設(shè)計(jì),大大提高了CPU的利用率。進(jìn)程的出現(xiàn)讓每個(gè)用戶(hù)感覺(jué)到自己獨(dú)享CPU,因此,進(jìn)程就是為了在CPU上實(shí)現(xiàn)多道編程而提出的。
有了進(jìn)程為什么還要線程?
進(jìn)程提供了多道編程,充分發(fā)揮了計(jì)算機(jī)部件的并行性,提高了計(jì)算機(jī)的利用率,既然進(jìn)程這么優(yōu)秀,為什么還要線程呢? 其實(shí),還是有很多缺陷的,主要體現(xiàn)在兩點(diǎn)上:
進(jìn)程只能在一個(gè)時(shí)間干一件事,如果想同時(shí)干兩件事或多件事,進(jìn)程就無(wú)能為力了。
進(jìn)程在執(zhí)行的過(guò)程中如果阻塞,例如等待輸入,整個(gè)進(jìn)程就會(huì)掛起,即使進(jìn)程中有些工作不依賴(lài)于輸入的數(shù)據(jù),也將無(wú)法執(zhí)行。
而解決辦法就是讓單個(gè)進(jìn)程,接受請(qǐng)求、等待I/O、處理計(jì)算并行起來(lái),這樣很明顯可以避免同步等待,提高執(zhí)行效率,在實(shí)際操作系統(tǒng)中這樣的機(jī)制就是——線程。
線程的優(yōu)點(diǎn)
因?yàn)橐l(fā),我們發(fā)明了進(jìn)程,又進(jìn)一步發(fā)明了線程。只不過(guò)進(jìn)程和線程的并發(fā)層次不同:進(jìn)程屬于在處理器這一層上提供的抽象;線程則屬于在進(jìn)程這個(gè)層次上再提供了一層并發(fā)的抽象。如果我們進(jìn)入計(jì)算機(jī)體系結(jié)構(gòu)里,就會(huì)發(fā)現(xiàn),流水線提供的也是一種并發(fā),不過(guò)是指令級(jí)的并發(fā)。這樣,流水線、線程、進(jìn)程就從低到高在三個(gè)層次上提供我們所迫切需要的并發(fā)!
除了提高進(jìn)程的并發(fā)度,線程還有個(gè)好處,就是可以有效地利用多處理器和多核計(jì)算機(jī),F(xiàn)在的處理器有個(gè)趨勢(shì)就是朝著多核方向發(fā)展,在沒(méi)有線程之前,多核并不能讓一個(gè)進(jìn)程的執(zhí)行速度提高,原因還是上面所有的兩點(diǎn)限制。但如果講一個(gè)進(jìn)程分解為若干個(gè)線程,則可以讓不同的線程運(yùn)行在不同的核上,從而提高了進(jìn)程的執(zhí)行速度。
例如:我們經(jīng)常使用微軟的Word進(jìn)行文字排版,實(shí)際上就打開(kāi)了多個(gè)線程。這些線程一個(gè)負(fù)責(zé)顯示,一個(gè)接受鍵盤(pán)的輸入,一個(gè)進(jìn)行存盤(pán)等等。這些線程一起運(yùn)行,讓我們感覺(jué)到我們輸入和屏幕顯示同時(shí)發(fā)生,而不是輸入一些字符,過(guò)一段時(shí)間才能看到顯示出來(lái)。在我們不經(jīng)意間,還進(jìn)行了自動(dòng)存盤(pán)操作。這就是線程給我們帶來(lái)的方便之處。
進(jìn)程與線程的區(qū)別
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。
線程是進(jìn)程的一個(gè)實(shí)體, 是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源。
一個(gè)線程可以創(chuàng)建和撤銷(xiāo)另一個(gè)線程,同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序 健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
Python 多進(jìn)程(multiprocessing)
Unix/Linux操作系統(tǒng)提供了一個(gè)fork()系統(tǒng)調(diào)用,它非常特殊。普通的函數(shù)調(diào)用,調(diào)用一次,返回一次,但是fork()調(diào)用一次,返回兩次,因?yàn)椴僮飨到y(tǒng)自動(dòng)把當(dāng)前進(jìn)程(稱(chēng)為父進(jìn)程)復(fù)制了一份(稱(chēng)為子進(jìn)程),然后,分別在父進(jìn)程和子進(jìn)程內(nèi)返回,
電腦資料
《Python 多進(jìn)程開(kāi)發(fā)與多線程開(kāi)發(fā)》(http://www.msguai.com)。子進(jìn)程永遠(yuǎn)返回0,而父進(jìn)程返回子進(jìn)程的ID。這樣做的理由是,一個(gè)父進(jìn)程可以fork出很多子進(jìn)程,所以,父進(jìn)程要記下每個(gè)子進(jìn)程的ID,而子進(jìn)程只需要調(diào)用getppid()就可以拿到父進(jìn)程的ID。
Python的os模塊封裝了常見(jiàn)的系統(tǒng)調(diào)用,其中就包括fork,可以在Python程序中輕松創(chuàng)建子進(jìn)程:
1
2
3
4
5
6
7
8
9
# multiprocessing.py
import os
print 'Process (%s) start...' % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
由于Windows沒(méi)有fork調(diào)用,上面的代碼在Windows上無(wú)法運(yùn)行。
multiprocessing
multiprocessing是跨平臺(tái)版本的多進(jìn)程模塊,它提供了一個(gè)Process類(lèi)來(lái)代表一個(gè)進(jìn)程對(duì)象,下面是示例代碼:
#!/usr/local/python27/bin/python2.7# coding=utf8# noinspection PyUnresolvedReferencesfrom multiprocessing import Processimport timedef f(n): time.sleep(1) print n*nfor i in range(10): p = Process(target=f,args=[i,]) p.start()
這個(gè)程序如果用單進(jìn)程寫(xiě)則需要執(zhí)行10秒以上的時(shí)間,而用多進(jìn)程則啟動(dòng)10個(gè)進(jìn)程并行執(zhí)行,只需要用1秒多的時(shí)間。
在一般情況下多個(gè)進(jìn)程的內(nèi)存資源是相互獨(dú)立的,而多線程可以共享同一個(gè)進(jìn)程中的內(nèi)存資源,示例代碼:
#!/usr/local/python27/bin/python2.7# coding=utf8# noinspection PyUnresolvedReferences# 通過(guò)多進(jìn)程和多線程對(duì)比,進(jìn)程間內(nèi)存無(wú)法共享,線程間的內(nèi)存共享from multiprocessing import Processimport threadingimport timelock = threading.Lock()def run(info_list,n): lock.acquire() info_list.append(n) lock.release() print('%s\n' % info_list)info = []for i in range(10):'''target為子進(jìn)程執(zhí)行的函數(shù),args為需要給函數(shù)傳遞的參數(shù)''' p = Process(target=run,args=[info,i]) p.start()'''這里是為了輸出整齊讓主進(jìn)程的執(zhí)行等一下子進(jìn)程''' time.sleep(1) print('------------threading--------------')for i in range(10): p = threading.Thread(target=run,args=[info,i]) p.start()