Python中的多進程是經過multiprocessing包來實現的,和多線程的threading.Thread差很少,它能夠利用multiprocessing.Process對象來建立一個進程對象。這個進程對象的方法和線程對象的方法差很少也有start(), run(), join()等方法,其中有一個方法不一樣Thread線程對象中的守護線程方法是setDeamon,而Process進程對象的守護進程是經過設置daemon屬性來完成的。python
下面說說Python多進程的實現方法,和多線程相似安全
from multiprocessing import Process
def fun1(name):
print('測試%s多進程' %name)
if __name__ == '__main__':
process_list = []
for i in range(5): #開啓5個子進程執行fun1函數
p = Process(target=fun1,args=('Python',)) #實例化進程對象
p.start()
process_list.append(p)
for i in process_list:
p.join()
print('結束測試')複製代碼
結果bash
測試Python多進程
測試Python多進程
測試Python多進程
測試Python多進程
測試Python多進程
結束測試
Process finished with exit code 0複製代碼
上面的代碼開啓了5個子進程去執行函數,咱們能夠觀察結果,是同時打印的,這裏實現了真正的並行操做,就是多個CPU同時執行任務。咱們知道進程是python中最小的資源分配單元,也就是進程中間的數據,內存是不共享的,每啓動一個進程,都要獨立分配資源和拷貝訪問的數據,因此進程的啓動和銷燬的代價是比較大了,因此在實際中使用多進程,要根據服務器的配置來設定。服務器
python開發IT技術交流羣:887934385 分享進階資源,視頻教程網絡
還記得python多線程的第二種實現方法嗎?是經過類繼承的方法來實現的,python多進程的第二種實現方式也是同樣的多線程
from multiprocessing import Process
class MyProcess(Process): #繼承Process類
def __init__(self,name):
super(MyProcess,self).__init__()
self.name = name
def run(self):
print('測試%s多進程' % self.name)
if __name__ == '__main__':
process_list = []
for i in range(5): #開啓5個子進程執行fun1函數
p = MyProcess('Python') #實例化進程對象
p.start()
process_list.append(p)
for i in process_list:
p.join()
print('結束測試')複製代碼
結果app
測試Python多進程
測試Python多進程
測試Python多進程
測試Python多進程
測試Python多進程
結束測試
Process finished with exit code 0複製代碼
效果和第一種方式同樣。dom
咱們能夠看到Python多進程的實現方式和多線程的實現方式幾乎同樣。異步
構造方法:
Process([group [, target [, name [, args [, kwargs]]]]])
group: 線程組
target: 要執行的方法
name: 進程名
args/kwargs: 要傳入方法的參數
實例方法:
is_alive():返回進程是否在運行,bool類型。
join([timeout]):阻塞當前上下文環境的進程程,直到調用此方法的進程終止或到達指定的timeout(可選參數)。
start():進程準備就緒,等待CPU調度
run():strat()調用run方法,若是實例進程時未制定傳入target,這star執行t默認run()方法。
terminate():無論任務是否完成,當即中止工做進程
屬性:
daemon:和線程的setDeamon功能同樣
name:進程名字
pid:進程號複製代碼
關於join,daemon的使用和python多線程同樣,這裏就不在複述了,你們能夠看看之前的python多線程系列文章。async
進程是系統獨立調度核分配系統資源(CPU、內存)的基本單位,進程之間是相互獨立的,每啓動一個新的進程至關於把數據進行了一次克隆,子進程裏的數據修改沒法影響到主進程中的數據,不一樣子進程之間的數據也不能共享,這是多進程在使用中與多線程最明顯的區別。可是難道Python多進程中間難道就是孤立的嗎?固然不是,python也提供了多種方法實現了多進程中間的通訊和數據共享(能夠修改一份數據)
Queue在多線程中也說到過,在生成者消費者模式中使用,是線程安全的,是生產者和消費者中間的數據管道,那在python多進程中,它其實就是進程之間的數據管道,實現進程通訊。
from multiprocessing import Process,Queue
def fun1(q,i):
print('子進程%s 開始put數據' %i)
q.put('我是%s 經過Queue通訊' %i)
if __name__ == '__main__':
q = Queue()
process_list = []
for i in range(3):
p = Process(target=fun1,args=(q,i,)) #注意args裏面要把q對象傳給咱們要執行的方法,這樣子進程才能和主進程用Queue來通訊
p.start()
process_list.append(p)
for i in process_list:
p.join()
print('主進程獲取Queue數據')
print(q.get())
print(q.get())
print(q.get())
print('結束測試')複製代碼
結果
子進程0 開始put數據
子進程1 開始put數據
子進程2 開始put數據
主進程獲取Queue數據
我是0 經過Queue通訊
我是1 經過Queue通訊
我是2 經過Queue通訊
結束測試
Process finished with exit code 0複製代碼
上面的代碼結果能夠看到咱們主進程中能夠經過Queue獲取子進程中put的數據,實現進程間的通訊。
管道Pipe和Queue的做用大體差很少,也是實現進程間的通訊,下面之間看怎麼使用吧
from multiprocessing import Process, Pipe
def fun1(conn):
print('子進程發送消息:')
conn.send('你好主進程')
print('子進程接受消息:')
print(conn.recv())
conn.close()
if __name__ == '__main__':
conn1, conn2 = Pipe() #關鍵點,pipe實例化生成一個雙向管
p = Process(target=fun1, args=(conn2,)) #conn2傳給子進程
p.start()
print('主進程接受消息:')
print(conn1.recv())
print('主進程發送消息:')
conn1.send("你好子進程")
p.join()
print('結束測試')複製代碼
結果
主進程接受消息:
子進程發送消息:
子進程接受消息:
你好主進程
主進程發送消息:
你好子進程
結束測試
Process finished with exit code 0複製代碼
上面能夠看到主進程和子進程能夠相互發送消息
Queue和Pipe只是實現了數據交互,並沒實現數據共享,即一個進程去更改另外一個進程的數據。那麼久要用到Managers
from multiprocessing import Process, Manager
def fun1(dic,lis,index):
dic[index] = 'a'
dic['2'] = 'b'
lis.append(index) #[0,1,2,3,4,0,1,2,3,4,5,6,7,8,9]
#print(l)
if __name__ == '__main__':
with Manager() as manager:
dic = manager.dict()#注意字典的聲明方式,不能直接經過{}來定義
l = manager.list(range(5))#[0,1,2,3,4]
process_list = []
for i in range(10):
p = Process(target=fun1, args=(dic,l,i))
p.start()
process_list.append(p)
for res in process_list:
res.join()
print(dic)
print(l)複製代碼
結果:
{0: 'a', '2': 'b', 3: 'a', 1: 'a', 2: 'a', 4: 'a', 5: 'a', 7: 'a', 6: 'a', 8: 'a', 9: 'a'}
[0, 1, 2, 3, 4, 0, 3, 1, 2, 4, 5, 7, 6, 8, 9]複製代碼
能夠看到主進程定義了一個字典和一個列表,在子進程中,能夠添加和修改字典的內容,在列表中插入新的數據,實現進程間的數據共享,便可以共同修改同一份數據
進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,若是進程池序列中沒有可供使用的進進程,那麼程序就會等待,直到進程池中有可用進程爲止。就是固定有幾個進程可使用。
進程池中有兩個方法:
apply:同步,通常不使用
apply_async:異步
from multiprocessing import Process,Pool
import os, time, random
def fun1(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
pool = Pool(5) #建立一個5個進程的進程池
for i in range(10):
pool.apply_async(func=fun1, args=(i,))
pool.close()
pool.join()
print('結束測試')複製代碼
結果
Run task 0 (37476)...
Run task 1 (4044)...
Task 0 runs 0.03 seconds.
Run task 2 (37476)...
Run task 3 (17252)...
Run task 4 (16448)...
Run task 5 (24804)...
Task 2 runs 0.27 seconds.
Run task 6 (37476)...
Task 1 runs 0.58 seconds.
Run task 7 (4044)...
Task 3 runs 0.98 seconds.
Run task 8 (17252)...
Task 5 runs 1.13 seconds.
Run task 9 (24804)...
Task 6 runs 1.46 seconds.
Task 4 runs 2.73 seconds.
Task 8 runs 2.18 seconds.
Task 7 runs 2.93 seconds.
Task 9 runs 2.93 seconds.
結束測試複製代碼
對Pool
對象調用join()
方法會等待全部子進程執行完畢,調用join()
以前必須先調用close()
,調用close()
以後就不能繼續添加新的Process
了。
案例來源於網絡,侵權請告知,謝謝
由於網上看到這個例子以爲不錯,因此這裏就不本身寫案例,這個案例比較有說服力
import os
import PIL
from multiprocessing import Pool
from PIL import Image
SIZE = (75,75)
SAVE_DIRECTORY = \'thumbs\'
def get_image_paths(folder):
return (os.path.join(folder, f)
for f in os.listdir(folder)
if \'jpeg\' in f)
def create_thumbnail(filename):
im = Image.open(filename)
im.thumbnail(SIZE, Image.ANTIALIAS)
base, fname = os.path.split(filename)
save_path = os.path.join(base, SAVE_DIRECTORY, fname)
im.save(save_path)
if __name__ == \'__main__\':
folder = os.path.abspath(
\'11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840\')
os.mkdir(os.path.join(folder, SAVE_DIRECTORY))
images = get_image_paths(folder)
pool = Pool()
pool.map(creat_thumbnail, images) #關鍵點,images是一個可迭代對象
pool.close()
pool.join()複製代碼
上邊這段代碼的主要工做就是將遍歷傳入的文件夾中的圖片文件,一一輩子成縮略圖,並將這些縮略圖保存到特定文件夾中。這個人機器上,用這一程序處理 6000 張圖片須要花費 27.9 秒。 map 函數並不支持手動線程管理,反而使得相關的 debug 工做也變得異常簡單。
map在爬蟲的領域裏也可使用,好比多個URL的內容爬取,能夠把URL放入元祖裏,而後傳給執行函數。
python開發IT技術交流羣:887934385 分享進階資源,視頻教程