摘要:多進程執(zhí)行任務結束,創(chuàng)建進程和銷毀進程是時間的,如果長度不夠,會造成多線程快過多進程多線程執(zhí)行任務結束,進程間通信生產(chǎn)者消費者模型與隊列演示了生產(chǎn)者和消費者的場景。
進程
Python是運行在解釋器中的語言,查找資料知道,python中有一個全局鎖(GIL),在使用多進程(Thread)的情況下,不能發(fā)揮多核的優(yōu)勢。而使用多進程(Multiprocess),則可以發(fā)揮多核的優(yōu)勢真正地提高效率。
如果多線程的進程是CPU密集型的,那多線程并不能有多少效率上的提升,相反還可能會因為線程的頻繁切換,導致效率下降,推薦使用多進程;如果是IO密集型,多線程的進程可以利用IO阻塞等待時的空閑時間執(zhí)行其他線程,提升效率。
1.Linux創(chuàng)建子進程的原理:
1). 父進程和子進程, 如果父進程結束, 子進程也隨之結束;
2). 先有父進程, 再有子進程, 通過fork函數(shù)實現(xiàn);
2.fork函數(shù)的返回值:調用該方法一次, 返回兩次;
產(chǎn)生的子進程返回一個0
父進程返回子進程的pid;
3.Window也能使用fork函數(shù)么?
Windows沒有fork函數(shù), Mac有fork函數(shù)(Unix -> Linux, Unix-> Mac), 封裝了一個模塊multiprocessing
4.常用方法:
os.fork()
os.getpid(): 獲取當前進程的pid;
os.getppid(): parent process id, 獲取當前進程的父進程的id號;
import os import time print("當前進程(pid=%d)正在運行..." %(os.getpid())) print("當前進程的父進程(pid=%d)正在運行..." %(os.getppid())) print("正在創(chuàng)建子進程......") pid = os.fork() pid2 = os.fork() print("第1個:", pid) print("第2個: ", pid2) if pid == 0: print("這是創(chuàng)建的子進程, 子進程的id為%s, 父進程的id為%s" %(os.getpid(), os.getppid())) else: print("當前是父進程[%s]的返回值%s" %(os.getpid(), pid)) time.sleep(100)win系統(tǒng)
在win系統(tǒng)下,使用實例化multiprocessing.Process創(chuàng)建進程須添加"if __name__=="__main__"",否則會出現(xiàn)以下報錯:
RuntimeError:
An attempt has been made to start a new process before the current process has finished its bootstrapping phase. This probably means that you are not using fork to start your child processes and you have forgotten to use the proper idiom in the main module: if __name__ == "__main__": freeze_support() ... The "freeze_support()" line can be omitted if the program is not going to be frozen to produce an executable.
import multiprocessing def job(): print("當前子進程的名稱為%s" %(multiprocessing.current_process())) if __name__=="__main__": #win操作系統(tǒng)需要加上,否則會出現(xiàn)異常報錯RuntimeError # 創(chuàng)建一個進程對象(group=None, target=None, name=None, args=(), kwargs={}) p1 = multiprocessing.Process(target=job) p2 = multiprocessing.Process(target=job) # 運行多進程, 執(zhí)行任務 p1.start() p2.start() # 等待所有的子進程執(zhí)行結束, 再執(zhí)行主進程的內容 p1.join() p2.join() print("任務執(zhí)行結束.......")通過重寫multiprocessing.Process類創(chuàng)建多進程
from multiprocessing import Process import multiprocessing class JobProcess(Process): # 重寫Process的構造方法, 獲取新的屬性 def __init__(self,queue): super(JobProcess, self).__init__() self.queue = queue # 重寫run方法, 將執(zhí)行的任務放在里面即可 def run(self): print("當前進程信息%s" %(multiprocessing.current_process())) if __name__=="__main__": processes = [] # 啟動10個子進程, 來處理需要執(zhí)行的任務; for i in range(10): #示例化類,創(chuàng)建進程 p = JobProcess(queue=3) processes.append(p) #啟動多進程,執(zhí)行任務 p.start() #等待所有的子進程結束,再執(zhí)行主進程 [pro.join() for pro in processes] print("任務執(zhí)行結束")守護進程
守護線程:
setDeamon: True: 主線程執(zhí)行結束, 子線程不再繼續(xù)執(zhí)行; Flase:
守護進程:
setDeamon: True: 主進程執(zhí)行結束, 子進程不再繼續(xù)執(zhí)行; Flase:
import multiprocessing import time def deamon(): #守護進程:當主程序運行結束,子進程也結束 name = multiprocessing.current_process() print("%s開始執(zhí)行" %(name)) time.sleep(3) print("執(zhí)行結束") if __name__=="__main__": p1 = multiprocessing.Process(target=deamon,name="hello") p1.daemon = True p1.start() time.sleep(2) print("整個程序執(zhí)行結束")終止進程
有些進程或許再執(zhí)行死循環(huán)任務,此時我們手動結束進程
terminate()
import multiprocessing import time def job(): name = multiprocessing.current_process() print("%s進程開啟" %(name)) time.sleep(3) print("進程結束") if __name__=="__main__": p = multiprocessing.Process(target=job) print("進程開啟:",p.is_alive()) p.start() print("進程開啟:",p.is_alive()) p.terminate() print("進程開啟:",p.is_alive()) time.sleep(0.001) print("進程開啟:",p.is_alive()) print("程序執(zhí)行結束")計算密集型和I/O密集型
計算密集型任務的特點是要進行大量的計算, 消耗CPU資源, 比如計算圓周率、 對視頻進行高清解碼等等, 全靠CPU的運算能力。 這種計算密集型任務雖然也可以用多任務完成, 但是任務越多, 花在任務切換的時間就越多, CPU執(zhí)行任務的效率就越低, 所以, 要最高效地利用CPU, 計算密集型任務同時進行的數(shù)量應當?shù)扔贑PU的核心數(shù)。計算密集型任務由于主要消耗CPU資源, 因此, 代碼運行效率至關重要。 Python這樣的腳本語言運行效率很低, 完全不適合計算密集型任務。 對于計算密集型任務,最好用C語言編寫。
第二種任務的類型是IO密集型, 涉及到網(wǎng)絡、 磁盤IO的任務都是IO密集型任務, 這類任務的特點是CPU消耗很少, 任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低于CPU和內存的速度)。對于IO密集型任務, 任務越多, CPU效率越高, 但也有一個限度。 常見的大部分任務都是IO密集型任務, 比如Web應用。
多進程和多線程對比多進程模式最大的優(yōu)點就是穩(wěn)定性高, 因為一個子進程崩潰了, 不會影響主進程和其他子進程。(當然主進程掛了所有進程就全掛了, 但是Master進程只負責分配任務, 掛掉的概率低)著名的Apache最早就是采用多進程模式。
多進程模式的缺點是創(chuàng)建進程的代價大, 在Unix/Linux系統(tǒng)下, 用 fork 調用還行, 在Windows下創(chuàng)建進程開銷巨大。 另外, 操作系統(tǒng)能同時運行的進程數(shù)也是有限的, 在內存和。CPU的限制下, 如果有幾千個進程同時運行, 操作系統(tǒng)連調度都會成問題。
多線程模式通常比多進程快一點, 但是也快不到哪去, 而且, 多線程模式致命的缺點就是任何一個線程掛掉都可能直接造成整個進程崩潰, 因為所有線程共享進程的內存。 在Windows上, 如果一個線程執(zhí)行的代碼出了問題, 你經(jīng)??梢钥吹竭@樣的提示:“該程序執(zhí)行了非法操作, 即將關閉”, 其實往往是某個線程出了問題, 但是操作系統(tǒng)會強制結束整個進程。
這里通過一個計算密集型任務,來測試多進程和多線程的執(zhí)行效率。
import multiprocessing import threading from mytimeit import timeit class JobProcess(multiprocessing.Process): def __init__(self,li): super(JobProcess, self).__init__() self.li = li def run(self): for i in self.li: sum(i) class JobThread(threading.Thread): def __init__(self,li): super(JobThread, self).__init__() self.li = li def run(self): for i in self.li: sum(i) @timeit def many_processs(): li = [[24892,23892348,239293,233],[2382394,49230,2321234],[48294,28420,29489]]*10 processes = [] for i in li : p = JobProcess(li) processes.append(p) p.start() [pro.join() for pro in processes] print("多進程執(zhí)行任務結束,?") @timeit def many_thread(): #創(chuàng)建進程和銷毀進程是時間的,如果li長度不夠,會造成多線程快過多進程 li = [[24892,23892348,239293,233],[2382394,49230,2321234],[48294,28420,29489]]*1000 threads = [] for i in li : t = JobThread(li) threads.append(t) t.start() [thread.join() for thread in threads] print("多線程執(zhí)行任務結束,?") if __name__ =="__main__": many_processs() many_thread()進程間通信-生產(chǎn)者消費者模型與隊列
演示了生產(chǎn)者和消費者的場景。生產(chǎn)者生產(chǎn)貨物,然后把貨物放到一個隊列之類的數(shù)據(jù)結構中,生產(chǎn)貨物所要花費的時間無法預先確定。消費者消耗生產(chǎn)者生產(chǎn)的貨物的時間也是不確定的。
通過隊列來實現(xiàn)進程間的通信
import multiprocessing import threading from multiprocessing import Queue class Producer(multiprocessing.Process): def __init__(self,queue): super(Producer, self).__init__() self.queue = queue def run(self): for i in range(13): #往隊列添加內容 self.queue.put(i) print("生產(chǎn)者傳遞的消息為%s" %(i)) return self.queue class Consumer(multiprocessing.Process): def __init__(self,queue): super(Consumer, self).__init__() self.queue = queue def run(self): #獲取隊列內容 #get會自動判斷隊列是否為空,如果是空, 跳出循環(huán), 不會再去從隊列獲取數(shù)據(jù); while True: print("進程獲取消息為:%s" %(self.queue.get())) if __name__=="__main__": queue = Queue(maxsize=100) p = Producer(queue) p.start() c = Consumer(queue) c.start() p.join() c.join(2) c.terminate() #終止進程 print("進程間通信結束,( ?? ω ?? )y")
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/42480.html
摘要:在一個進程內部,要同時干多件事,就需要同時運行多個子任務,我們把進程內的這些子任務稱為線程??偨Y一下,多任務的實現(xiàn)方式有三種多進程模式多線程模式多進程多線程模式線程是最小的執(zhí)行單元,而進程由至少一個線程組成。 進程與線程 很多同學都聽說過,現(xiàn)代操作系統(tǒng)比如Mac OS X,UNIX,Linux,Windows等,都是支持多任務的操作系統(tǒng)。 什么叫多任務呢?簡單地說,就是操作系統(tǒng)可以同時...
摘要:分布式進程在和中,應當優(yōu)選,因為更穩(wěn)定,而且,可以分布到多臺機器上,而最多只能分布到同一臺機器的多個上。由于模塊封裝很好,不必了解網(wǎng)絡通信的細節(jié),就可以很容易地編寫分布式多進程程序。 分布式進程 在Thread和Process中,應當優(yōu)選Process,因為Process更穩(wěn)定,而且,Process可以分布到多臺機器上,而Thread最多只能分布到同一臺機器的多個CPU上。 Pytho...
摘要:協(xié)程,又稱微線程,纖程。最大的優(yōu)勢就是協(xié)程極高的執(zhí)行效率。生產(chǎn)者產(chǎn)出第條數(shù)據(jù)返回更新值更新消費者正在調用第條數(shù)據(jù)查看當前進行的線程函數(shù)中有,返回值為生成器庫實現(xiàn)協(xié)程通過提供了對協(xié)程的基本支持,但是不完全。 協(xié)程,又稱微線程,纖程。英文名Coroutine協(xié)程看上去也是子程序,但執(zhí)行過程中,在子程序內部可中斷,然后轉而執(zhí)行別的子程序,在適當?shù)臅r候再返回來接著執(zhí)行。 最大的優(yōu)勢就是協(xié)程極高...
摘要:協(xié)程實現(xiàn)連接在網(wǎng)絡通信中,每個連接都必須創(chuàng)建新線程或進程來處理,否則,單線程在處理連接的過程中,無法接受其他客戶端的連接。所以我們嘗試使用協(xié)程來實現(xiàn)服務器對多個客戶端的響應。 協(xié)程實現(xiàn)TCP連接 在網(wǎng)絡通信中,每個連接都必須創(chuàng)建新線程(或進程) 來處理,否則,單線程在處理連接的過程中, 無法接受其他客戶端的連接。所以我們嘗試使用協(xié)程來實現(xiàn)服務器對多個客戶端的響應。與單一TCP通信的構架...
摘要:一個包來了之后,到底是交給瀏覽器還是,就需要端口號來區(qū)分。每個網(wǎng)絡程序都向操作系統(tǒng)申請唯一的端口號,這樣,兩個進程在兩臺計算機之間建立網(wǎng)絡連接就需要各自的地址和各自的端口號。 網(wǎng)絡通信的三要素 IP 通信的時候, 雙方必須知道對方的標識, 好比發(fā)郵件必須知道對方的郵件地址。 互聯(lián)網(wǎng)上每個計算機的唯一標識就是IP地址, 類似 123.123.123.123 。 IP地址實際上是一個32位...
閱讀 2798·2021-11-22 13:54
閱讀 1149·2021-10-14 09:48
閱讀 2358·2021-09-08 09:35
閱讀 1609·2019-08-30 15:53
閱讀 1215·2019-08-30 13:14
閱讀 676·2019-08-30 13:09
閱讀 2588·2019-08-30 10:57
閱讀 3390·2019-08-29 13:18