摘要:多進程執行任務結束,創建進程和銷毀進程是時間的,如果長度不夠,會造成多線程快過多進程多線程執行任務結束,進程間通信生產者消費者模型與隊列演示了生產者和消費者的場景。
進程
Python是運行在解釋器中的語言,查找資料知道,python中有一個全局鎖(GIL),在使用多進程(Thread)的情況下,不能發揮多核的優勢。而使用多進程(Multiprocess),則可以發揮多核的優勢真正地提高效率。
如果多線程的進程是CPU密集型的,那多線程并不能有多少效率上的提升,相反還可能會因為線程的頻繁切換,導致效率下降,推薦使用多進程;如果是IO密集型,多線程的進程可以利用IO阻塞等待時的空閑時間執行其他線程,提升效率。
1.Linux創建子進程的原理:
1). 父進程和子進程, 如果父進程結束, 子進程也隨之結束;
2). 先有父進程, 再有子進程, 通過fork函數實現;
2.fork函數的返回值:調用該方法一次, 返回兩次;
產生的子進程返回一個0
父進程返回子進程的pid;
3.Window也能使用fork函數么?
Windows沒有fork函數, Mac有fork函數(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("正在創建子進程......") pid = os.fork() pid2 = os.fork() print("第1個:", pid) print("第2個: ", pid2) if pid == 0: print("這是創建的子進程, 子進程的id為%s, 父進程的id為%s" %(os.getpid(), os.getppid())) else: print("當前是父進程[%s]的返回值%s" %(os.getpid(), pid)) time.sleep(100)win系統
在win系統下,使用實例化multiprocessing.Process創建進程須添加"if __name__=="__main__"",否則會出現以下報錯:
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操作系統需要加上,否則會出現異常報錯RuntimeError # 創建一個進程對象(group=None, target=None, name=None, args=(), kwargs={}) p1 = multiprocessing.Process(target=job) p2 = multiprocessing.Process(target=job) # 運行多進程, 執行任務 p1.start() p2.start() # 等待所有的子進程執行結束, 再執行主進程的內容 p1.join() p2.join() print("任務執行結束.......")通過重寫multiprocessing.Process類創建多進程
from multiprocessing import Process import multiprocessing class JobProcess(Process): # 重寫Process的構造方法, 獲取新的屬性 def __init__(self,queue): super(JobProcess, self).__init__() self.queue = queue # 重寫run方法, 將執行的任務放在里面即可 def run(self): print("當前進程信息%s" %(multiprocessing.current_process())) if __name__=="__main__": processes = [] # 啟動10個子進程, 來處理需要執行的任務; for i in range(10): #示例化類,創建進程 p = JobProcess(queue=3) processes.append(p) #啟動多進程,執行任務 p.start() #等待所有的子進程結束,再執行主進程 [pro.join() for pro in processes] print("任務執行結束")守護進程
守護線程:
setDeamon: True: 主線程執行結束, 子線程不再繼續執行; Flase:
守護進程:
setDeamon: True: 主進程執行結束, 子進程不再繼續執行; Flase:
import multiprocessing import time def deamon(): #守護進程:當主程序運行結束,子進程也結束 name = multiprocessing.current_process() print("%s開始執行" %(name)) time.sleep(3) print("執行結束") if __name__=="__main__": p1 = multiprocessing.Process(target=deamon,name="hello") p1.daemon = True p1.start() time.sleep(2) print("整個程序執行結束")終止進程
有些進程或許再執行死循環任務,此時我們手動結束進程
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("程序執行結束")計算密集型和I/O密集型
計算密集型任務的特點是要進行大量的計算, 消耗CPU資源, 比如計算圓周率、 對視頻進行高清解碼等等, 全靠CPU的運算能力。 這種計算密集型任務雖然也可以用多任務完成, 但是任務越多, 花在任務切換的時間就越多, CPU執行任務的效率就越低, 所以, 要最高效地利用CPU, 計算密集型任務同時進行的數量應當等于CPU的核心數。計算密集型任務由于主要消耗CPU資源, 因此, 代碼運行效率至關重要。 Python這樣的腳本語言運行效率很低, 完全不適合計算密集型任務。 對于計算密集型任務,最好用C語言編寫。
第二種任務的類型是IO密集型, 涉及到網絡、 磁盤IO的任務都是IO密集型任務, 這類任務的特點是CPU消耗很少, 任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低于CPU和內存的速度)。對于IO密集型任務, 任務越多, CPU效率越高, 但也有一個限度。 常見的大部分任務都是IO密集型任務, 比如Web應用。
多進程和多線程對比多進程模式最大的優點就是穩定性高, 因為一個子進程崩潰了, 不會影響主進程和其他子進程。(當然主進程掛了所有進程就全掛了, 但是Master進程只負責分配任務, 掛掉的概率低)著名的Apache最早就是采用多進程模式。
多進程模式的缺點是創建進程的代價大, 在Unix/Linux系統下, 用 fork 調用還行, 在Windows下創建進程開銷巨大。 另外, 操作系統能同時運行的進程數也是有限的, 在內存和。CPU的限制下, 如果有幾千個進程同時運行, 操作系統連調度都會成問題。
多線程模式通常比多進程快一點, 但是也快不到哪去, 而且, 多線程模式致命的缺點就是任何一個線程掛掉都可能直接造成整個進程崩潰, 因為所有線程共享進程的內存。 在Windows上, 如果一個線程執行的代碼出了問題, 你經常可以看到這樣的提示:“該程序執行了非法操作, 即將關閉”, 其實往往是某個線程出了問題, 但是操作系統會強制結束整個進程。
這里通過一個計算密集型任務,來測試多進程和多線程的執行效率。
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("多進程執行任務結束,?") @timeit def many_thread(): #創建進程和銷毀進程是時間的,如果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("多線程執行任務結束,?") if __name__ =="__main__": many_processs() many_thread()進程間通信-生產者消費者模型與隊列
演示了生產者和消費者的場景。生產者生產貨物,然后把貨物放到一個隊列之類的數據結構中,生產貨物所要花費的時間無法預先確定。消費者消耗生產者生產的貨物的時間也是不確定的。
通過隊列來實現進程間的通信
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("生產者傳遞的消息為%s" %(i)) return self.queue class Consumer(multiprocessing.Process): def __init__(self,queue): super(Consumer, self).__init__() self.queue = queue def run(self): #獲取隊列內容 #get會自動判斷隊列是否為空,如果是空, 跳出循環, 不會再去從隊列獲取數據; 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")
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42480.html
摘要:在一個進程內部,要同時干多件事,就需要同時運行多個子任務,我們把進程內的這些子任務稱為線程。總結一下,多任務的實現方式有三種多進程模式多線程模式多進程多線程模式線程是最小的執行單元,而進程由至少一個線程組成。 進程與線程 很多同學都聽說過,現代操作系統比如Mac OS X,UNIX,Linux,Windows等,都是支持多任務的操作系統。 什么叫多任務呢?簡單地說,就是操作系統可以同時...
摘要:分布式進程在和中,應當優選,因為更穩定,而且,可以分布到多臺機器上,而最多只能分布到同一臺機器的多個上。由于模塊封裝很好,不必了解網絡通信的細節,就可以很容易地編寫分布式多進程程序。 分布式進程 在Thread和Process中,應當優選Process,因為Process更穩定,而且,Process可以分布到多臺機器上,而Thread最多只能分布到同一臺機器的多個CPU上。 Pytho...
摘要:協程,又稱微線程,纖程。最大的優勢就是協程極高的執行效率。生產者產出第條數據返回更新值更新消費者正在調用第條數據查看當前進行的線程函數中有,返回值為生成器庫實現協程通過提供了對協程的基本支持,但是不完全。 協程,又稱微線程,纖程。英文名Coroutine協程看上去也是子程序,但執行過程中,在子程序內部可中斷,然后轉而執行別的子程序,在適當的時候再返回來接著執行。 最大的優勢就是協程極高...
摘要:協程實現連接在網絡通信中,每個連接都必須創建新線程或進程來處理,否則,單線程在處理連接的過程中,無法接受其他客戶端的連接。所以我們嘗試使用協程來實現服務器對多個客戶端的響應。 協程實現TCP連接 在網絡通信中,每個連接都必須創建新線程(或進程) 來處理,否則,單線程在處理連接的過程中, 無法接受其他客戶端的連接。所以我們嘗試使用協程來實現服務器對多個客戶端的響應。與單一TCP通信的構架...
摘要:一個包來了之后,到底是交給瀏覽器還是,就需要端口號來區分。每個網絡程序都向操作系統申請唯一的端口號,這樣,兩個進程在兩臺計算機之間建立網絡連接就需要各自的地址和各自的端口號。 網絡通信的三要素 IP 通信的時候, 雙方必須知道對方的標識, 好比發郵件必須知道對方的郵件地址。 互聯網上每個計算機的唯一標識就是IP地址, 類似 123.123.123.123 。 IP地址實際上是一個32位...
閱讀 2722·2021-11-22 13:54
閱讀 1063·2021-10-14 09:48
閱讀 2292·2021-09-08 09:35
閱讀 1550·2019-08-30 15:53
閱讀 1166·2019-08-30 13:14
閱讀 606·2019-08-30 13:09
閱讀 2521·2019-08-30 10:57
閱讀 3334·2019-08-29 13:18