本篇文章主要介紹了詳解python之多進程和進程池(Processing庫),非常具有實用價值,需要的朋友可以參考下
環境:win7+python2.7
一直想學習多進程或多線程,但之前只是單純看一點基礎知識還有簡單的介紹,無法理解怎麼去應用,直到前段時間看了github的一個爬蟲項目涉及到多進程,多執行緒相關內容,一邊看一邊百度相關知識點,現在把一些相關知識點和一些應用寫下來做個記錄.
首先說下什麼是進程:進程是程式在電腦上的一次執行活動,當運行一個程式的時候,就啟動了一個進程.而進程又分為系統進程和用戶進程.只要是用於完成操作系統的各種功能的進程就是系統進程,它們就是處於運行狀態下的作業系統本身;而所有由你啟動的進程都是使用者進程。進程是作業系統進行資源分配的單位。
直觀點說,在任務管理器的用戶名上標明system的是系統進程,標明administrator的是用戶進程,另外net是網洛,lcacal service是本地服務,關於進程更加具體的信息可以百科,這裡得省點力氣,不然收不回了.
一.多進程的簡單使用
如圖,multiprocessing有多個函數,很多我也還沒去了解,這裡只講我目前了解的.
#進程創建:Process(target=主要運行的函數,name=自訂進程名稱可不寫,args=(參數))
方法:
#is_alive():判斷進程是否存活
其中,Process以start()啟動某個行程。
屬性:
1.Process(),start(),join()
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p2.start() p1.join() p2.join() b=time.time() print 'finish',b-a
這裡一共開了兩個行程,p1和p2, arg=(4,)中的4是fun1函數的參數,這裡要用tulpe類型,如果兩個參數或更多就是arg=(參數1,參數2...),之後用start()啟動進程,我們設定等待p1和p2進程結束再執行下一步.來看下面的運行結果,fun2和fun1基本上在同一時間開始運行,當運行完畢(fun1睡眠4秒,同時fun2睡眠6秒),才執行print ' finish',b-a語句
this is fun2 Mon Jun 05 13:48:04 2017 this is fun1 Mon Jun 05 13:48:04 2017 fun1 finish Mon Jun 05 13:48:08 2017 fun2 finish Mon Jun 05 13:48:10 2017 finish 6.20300006866 Process finished with exit code 0
我們再來看下start()與join()處於不同位置會發生什麼
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p1.join() p2.start() p2.join() b=time.time() print 'finish',b-a
結果:
this is fun1 Mon Jun 05 14:19:28 2017 fun1 finish Mon Jun 05 14:19:32 2017 this is fun2 Mon Jun 05 14:19:32 2017 fun2 finish Mon Jun 05 14:19:38 2017 finish 10.1229999065 Process finished with exit code 0
看,現在是先運行fun1函數,運行完畢再運行fun2接著再是print 'finish',即先運行進程p1再運行進程p2,感受到join()的魅力了吧.現在再試試註釋掉join()看看又會出現什麼
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p2.start() p1.join() #p2.join() b=time.time() print 'finish',b-a
結果:
this is fun1 Mon Jun 05 14:23:57 2017 this is fun2 Mon Jun 05 14:23:58 2017 fun1 finish Mon Jun 05 14:24:01 2017 finish 4.05900001526 fun2 finish Mon Jun 05 14:24:04 2017 Process finished with exit code 0這次是運行完fun1(因為p1進程有用join(),所以主程式等待p1運行完接著執行下一步),接著繼續運行主進程的print 'finish',最後fun2運行完畢才結束
2.name,daemon,is_alive():
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() p1=Process(name='fun1进程',target=fun1,args=(4,)) p2 = Process(name='fun2进程',target=fun2, args=(6,)) p1.daemon=True p2.daemon = True p1.start() p2.start() p1.join() print p1,p2 print '进程1:',p1.is_alive(),'进程2:',p2.is_alive() #p2.join() b=time.time() print 'finish',b-a
#結果:
this is fun2 Mon Jun 05 14:43:49 2017 this is fun1 Mon Jun 05 14:43:49 2017 fun1 finish Mon Jun 05 14:43:53 2017 <Process(fun1进程, stopped daemon)> <Process(fun2进程, started daemon)> 进程1: False 进程2: True finish 4.06500005722 Process finished with exit code 0
可以看到,name是給進程賦予名字, 運行到print '進程1:',p1.is_alive(),'進程2:',p2.is_alive() 這句話的時候,p1進程已經結束(返回False),p2進程仍在運行(返回True),但p2沒有用join(),所以直接接著執行主進程,由於用了daemon=Ture,父進程終止後自動終止,p2進程沒有結束就強行結束整個程式了.
3.run()run()在Process沒有指定target函數時,預設用run()函數執行程式,
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a = time.time() p=Process() p.start() p.join() b = time.time() print 'finish', b - a
結果:
finish 0.0840001106262從結果看出,進程p什麼也沒做,為了讓進程正常運作,我們醬紫寫:
目標函數沒有參數:
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(): print 'this is fun1',time.ctime() time.sleep(2) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a = time.time() p=Process() p.run=fun1 p.start() p.join() b = time.time() print 'finish', b - a
結果:
this is fun1 Mon Jun 05 16:34:41 2017 fun1 finish Mon Jun 05 16:34:43 2017 finish 2.11500000954 Process finished with exit code 0
目標函數有參數:
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a = time.time() p=Process() p.run=fun1(2) p.start() p.join() b = time.time() print 'finish', b - a
結果:
this is fun1 Mon Jun 05 16:36:27 2017 fun1 finish Mon Jun 05 16:36:29 2017 Process Process-1: Traceback (most recent call last): File "E:\Anaconda2\lib\multiprocessing\process.py", line 258, in _bootstrap self.run() TypeError: 'NoneType' object is not callable finish 2.0529999733 Process finished with exit code 0
目標函數有參數的出現了異常,為什麼呢?我現在還找不到原因,但是實踐發現,當最後一個參數賦予進程運行後,沒有其他參數,就會出現這個異常,有人知道的望告知.
二.進程池# #####对于需要使用几个甚至十几个进程时,我们使用Process还是比较方便的,但是如果要成百上千个进程,用Process显然太笨了,multiprocessing提供了Pool类,即现在要讲的进程池,能够将众多进程放在一起,设置一个运行进程上限,每次只运行设置的进程数,等有进程结束,再添加新的进程
Pool(processes =num):设置运行进程数,当一个进程运行完,会添加新的进程进去
apply_async(函数,(参数)):非阻塞,其中参数是tulpe类型,
apply(函数,(参数)):阻塞
close():关闭pool,不能再添加新的任务
terminate():结束运行的进程,不再处理未完成的任务
join():和Process介绍的作用一样, 但要在close或terminate之后使用。
1.单个进程池
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() pool = Pool(processes =3) # 可以同时跑3个进程 for i in range(3,8): pool.apply_async(fun1,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
结果:
this is fun1 Mon Jun 05 15:15:38 2017 this is fun1 Mon Jun 05 15:15:38 2017 this is fun1 Mon Jun 05 15:15:38 2017 fun1 finish Mon Jun 05 15:15:41 2017 this is fun1 Mon Jun 05 15:15:41 2017 fun1 finish Mon Jun 05 15:15:42 2017 this is fun1 Mon Jun 05 15:15:42 2017 fun1 finish Mon Jun 05 15:15:43 2017 fun1 finish Mon Jun 05 15:15:47 2017 fun1 finish Mon Jun 05 15:15:49 2017 finish 11.1370000839 Process finished with exit code 0
从上面的结果可以看到,设置了3个运行进程上限,15:15:38这个时间同时开始三个进程,当第一个进程结束时(参数为3秒那个进程),会添加新的进程,如此循环,直至进程池运行完再执行主进程语句b=time.time() print 'finish',b-a .这里用到非阻塞apply_async(),再来对比下阻塞apply()
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() pool = Pool(processes =3) # 可以同时跑3个进程 for i in range(3,8): pool.apply(fun1,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
结果:
this is fun1 Mon Jun 05 15:59:26 2017 fun1 finish Mon Jun 05 15:59:29 2017 this is fun1 Mon Jun 05 15:59:29 2017 fun1 finish Mon Jun 05 15:59:33 2017 this is fun1 Mon Jun 05 15:59:33 2017 fun1 finish Mon Jun 05 15:59:38 2017 this is fun1 Mon Jun 05 15:59:38 2017 fun1 finish Mon Jun 05 15:59:44 2017 this is fun1 Mon Jun 05 15:59:44 2017 fun1 finish Mon Jun 05 15:59:51 2017 finish 25.1610000134 Process finished with exit code 0
可以看到,阻塞是当一个进程结束后,再进行下一个进程,一般我们都用非阻塞apply_async()
2.多个进程池
上面是使用单个进程池的,对于多个进程池,我们可以用for循环,直接看代码
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if name == 'main': a=time.time() pool = Pool(processes =3) # 可以同时跑3个进程 for fun in [fun1,fun2]: for i in range(3,8): pool.apply_async(fun,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
结果:
this is fun1 Mon Jun 05 16:04:38 2017 this is fun1 Mon Jun 05 16:04:38 2017 this is fun1 Mon Jun 05 16:04:38 2017 fun1 finish Mon Jun 05 16:04:41 2017 this is fun1 Mon Jun 05 16:04:41 2017 fun1 finish Mon Jun 05 16:04:42 2017 this is fun1 Mon Jun 05 16:04:42 2017 fun1 finish Mon Jun 05 16:04:43 2017 this is fun2 Mon Jun 05 16:04:43 2017 fun2 finish Mon Jun 05 16:04:46 2017 this is fun2 Mon Jun 05 16:04:46 2017 fun1 finish Mon Jun 05 16:04:47 2017 this is fun2 Mon Jun 05 16:04:47 2017 fun1 finish Mon Jun 05 16:04:49 2017 this is fun2 Mon Jun 05 16:04:49 2017 fun2 finish Mon Jun 05 16:04:50 2017 this is fun2 Mon Jun 05 16:04:50 2017 fun2 finish Mon Jun 05 16:04:52 2017 fun2 finish Mon Jun 05 16:04:55 2017 fun2 finish Mon Jun 05 16:04:57 2017 finish 19.1670000553 Process finished with exit code 0
看到了,在fun1运行完接着运行fun2.
另外对于没有参数的情况,就直接 pool.apply_async(funtion),无需写上参数.
在学习编写程序过程,曾遇到不用if _name_ == '_main_':而直接运行程序,这样结果会出错,经查询,在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的if _name_ == ‘_main_' :语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要。原因有人这么说:在执行的時候,由于你写的 py 会被当成module 读进执行。所以,一定要判断自身是否为 _main_。也就是要:
if name == ‘main' : # do something.
这里我自己还搞不清楚,期待以后能够理解
以上是python中多進程和進程池(Processing庫)的實例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!