python並發執行之多進程
- 2020 年 1 月 8 日
- 筆記
多進程顧名思義程序啟動的時候運行多個進程,每個進程啟動一條線程進行程序處理。 沒啟動一個進程就要單獨劃分一塊內存資源。就像工廠的廠房。為了提高效率每多添加一條生產線就要單獨再蓋一個廠房。每個廠房相互是獨立的。所以啟動多進程是很消耗資源的,畢竟廠房蓋多了廠區就沒地方給其他設施用了。
多進程的代碼實現方法和多線程的函數方式很類似
#!/usr/bin/env python # -*-coding:utf-8-*- from multiprocessing import Process #引用的模塊變成了多進程模塊 def foo(i): print 'say hi',i for i in range(10): """ 同時啟動10個進程,把Process()實例化給p 調用p.start()方法啟動每個進程 """ p = Process(target=foo,args=(i,)) p.start()
上面提到了多進程之間數據是相互獨立的,我們來寫一段代碼測試一下
#!/usr/bin/env python #coding:utf-8 from multiprocessing import Process li = [] def foo(i): #向列表中加入當前的進程序列號 li.append(i) print 'say hi',li for i in range(10): p = Process(target=foo,args=(i,)) p.start() print 'ending',li
上面的代碼運行結果是
[wgw@mail ~]$ python test.py say hi [0] say hi [1] say hi [2] say hi [3] say hi [4] say hi [5] say hi [6] say hi [7] say hi [8] ending [] say hi [9]
注意看ending [] 這一列。通過代碼我們得知每個一個派生的子進程都會調用foo()函數並將自己的進程運行序列號添加到li表中。但是當最後我們要查看li[]表裡存儲的內容,我們並沒有看到自己希望看到[0,1,2…9]的內容這是為什麼呢?這其實就是進程的內存相互獨立導致的。我們創建了進程0,那麼進程就複製了一個空列表li[],並把0追加到表裡。那麼對於進程0來說li列表的內容就是li[0]。但是進程1在啟動之後也和進程0一樣複製了一個空列表li[],對於進程1來說運行結束時候自己的列表li的內容就是li[1]。以此類推,啟動了10個子進程就複製了10個li[]空列表。每個進程中的列表都是相互獨立的,而程序的最後我們打印的是最主進程的那個li[]列表,這個列表沒有被操作過所以還是空的。通過這裡我們也可以得知,多進程的時候每個進程都要對資源進行複製。所以進程啟動多了會異常的消耗資源。
如果我們要讓進程間數據同步,就需要藉助multiprocessing模塊中的Manager方法來管理特殊的列表或者字典。通過這種特殊方法來實現進程間數據的同步。看代碼
#!/usr/bin/env python # -*-coding:utf-8-*- from multiprocessing import Process,Manager def foo(i,Manger_list): """ 函數要引用別Manger方法管理的特殊列表,這列表的 操作和標準列表是完全一致的。 """ Manger_list.append(i) print 'say hi',li if __name__=='__main__': #定義一個空列表儲存生成的多進程句柄 p_list=[] #實例化Manager方法 manager=Manager() #聲明li是被manger管理的特殊列表 li = manager.list() for i in range(10): #將進程的啟動序列號和特殊列表賦值給foo()函數 p = Process(target=foo,args=(i,li)) p_list.append(p) for p in p_list: #執行多進程句柄,交給CPU調度 p.start() for p in p_list: #在最後一個子進程結束前,不能停止主進程 p.join() #主進程結束後打印主進程中li列表的內容 print 'ending',li
這段代碼的運行結果是
say hi [0] say hi [0, 7] say hi [0, 7, 4] say hi [0, 7, 4, 5] say hi [0, 7, 4, 5, 6] say hi [0, 7, 4, 5, 6, 2] say hi [0, 7, 4, 5, 6, 2, 9] say hi [0, 7, 4, 5, 6, 2, 9, 3] say hi [0, 7, 4, 5, 6, 2, 9, 3, 8] say hi [0, 7, 4, 5, 6, 2, 9, 3, 8, 1] ending [0, 7, 4, 5, 6, 2, 9, 3, 8, 1]
從上面的結果就可以看出來,雖然進程執行結束的順序和啟動時候的順序不一樣了。但是每個子進程的執行結果都被追加到了同一個li列表中。並且最後主進程的li列表內容和子進程的的內容一致。說明通過multiprocessing.Manager()方法可以讓多進程像多線程一樣實現內存數據的共享。