Python 多程式 multiprocessing.Pool類詳解
multiprocessing模組
multiprocessing包是Python中的多程式管理包。它與 threading.Thread類似,可以利用multiprocessing.Process物件來建立一個程式。該程式可以允許放在Python程式內部編寫的函式中。該Process物件與Thread物件的用法相同,擁有is_alive()、join([timeout])、run()、start()、terminate()等方法。屬性有:authkey、daemon(要通過start()設定)、exitcode(程式在執行時為None、如果為–N,表示被訊號N結束)、name、pid。此外multiprocessing包中也有Lock/Event/Semaphore/Condition類,用來同步程式,其用法也與threading包中的同名類一樣。multiprocessing的很大一部份與threading使用同一套API,只不過換到了多程式的情境。
這個模組表示像執行緒一樣管理程式,這個是multiprocessing的核心,它與threading很相似,對多核CPU的利用率會比threading好的多。
看一下Process類的構造方法:
__init__(self, group=None, target=None, name=None, args=(), kwargs={})
引數說明:
group:程式所屬組。基本不用
target:表示呼叫物件。
args:表示呼叫物件的位置引數元組。
name:別名
kwargs:表示呼叫物件的字典。
建立程式的簡單例項:
#coding=utf-8
import multiprocessing
def do(n) :
#獲取當前執行緒的名字
name = multiprocessing.current_process().name
print name,'starting'
print "worker ", n
return
if __name__ == '__main__' :
numList = []
for i in xrange(5) :
p = multiprocessing.Process(target=do, args=(i,))
numList.append(p)
p.start()
p.join()
print "Process end."
執行結果:
Process-1 starting
worker 0
Process end.
Process-2 starting
worker 1
Process end.
Process-3 starting
worker 2
Process end.
Process-4 starting
worker 3
Process end.
Process-5 starting
worker 4
Process end.
建立子程式時,只需要傳入一個執行函式和函式的引數,建立一個Process例項,並用其start()方法啟動,這樣建立程式比fork()還要簡單。
join()方法表示等待子程式結束以後再繼續往下執行,通常用於程式間的同步。
注意:
在Windows上要想使用程式模組,就必須把有關程式的程式碼寫在當前.py檔案的if __name__ == ‘__main__’ :語句的下面,才能正常使用Windows下的程式模組。Unix/Linux下則不需要。
Pool類
在使用Python進行系統管理時,特別是同時操作多個檔案目錄或者遠端控制多臺主機,並行操作可以節約大量的時間。如果操作的物件數目不大時,還可以直接使用Process類動態的生成多個程式,十幾個還好,但是如果上百個甚至更多,那手動去限制程式數量就顯得特別的繁瑣,此時程式池就派上用場了。
Pool類可以提供指定數量的程式供使用者呼叫,當有新的請求提交到Pool中時,如果池還沒有滿,就會建立一個新的程式來執行請求。如果池滿,請求就會告知先等待,直到池中有程式結束,才會建立新的程式來執行這些請求。
下面介紹一下multiprocessing 模組下的Pool類下的幾個方法
apply()
函式原型:
apply(func[, args=()[, kwds={}]])
該函式用於傳遞不定引數,主程式會被阻塞直到函式執行結束(不建議使用,並且3.x以後不在出現)。
apply_async()
函式原型:
apply_async(func[, args=()[, kwds={}[, callback=None]]])
與apply用法一樣,但它是非阻塞且支援結果返回進行回撥。
map()
函式原型:
map(func, iterable[, chunksize=None])
Pool類中的map方法,與內建的map函式用法行為基本一致,它會使程式阻塞直到返回結果。
注意,雖然第二個引數是一個迭代器,但在實際使用中,必須在整個佇列都就緒後,程式才會執行子程式。
close()
關閉程式池(pool),使其不在接受新的任務。
terminate()
結束工作程式,不在處理未處理的任務。
join()
主程式阻塞等待子程式的退出,join方法必須在close或terminate之後使用。
multiprocessing.Pool類的例項:
import time
from multiprocessing import Pool
def run(fn):
#fn: 函式引數是資料列表的一個元素
time.sleep(1)
return fn*fn
if __name__ == "__main__":
testFL = [1,2,3,4,5,6]
print 'shunxu:' #順序執行(也就是序列執行,單程式)
s = time.time()
for fn in testFL:
run(fn)
e1 = time.time()
print "順序執行時間:", int(e1 - s)
print 'concurrent:' #建立多個程式,並行執行
pool = Pool(5) #建立擁有5個程式數量的程式池
#testFL:要處理的資料列表,run:處理testFL列表中資料的函式
rl =pool.map(run, testFL)
pool.close()#關閉程式池,不再接受新的程式
pool.join()#主程式阻塞等待子程式的退出
e2 = time.time()
print "並行執行時間:", int(e2-e1)
print rl
執行結果:
shunxu:
順序執行時間: 6
concurrent:
並行執行時間: 2
[1, 4, 9, 16, 25, 36]
上例是一個建立多個程式併發處理與順序執行處理同一資料,所用時間的差別。從結果可以看出,併發執行的時間明顯比順序執行要快很多,但是程式是要耗資源的,所以平時工作中,程式數也不能開太大。
程式中的r1表示全部程式執行結束後全域性的返回結果集,run函式有返回值,所以一個程式對應一個返回結果,這個結果存在一個列表中,也就是一個結果堆中,實際上是用了佇列的原理,等待所有程式都執行完畢,就返回這個列表(列表的順序不定)。
對Pool物件呼叫join()方法會等待所有子程式執行完畢,呼叫join()之前必須先呼叫close(),讓其不再接受新的Process了。
再看一個例項:
import time
from multiprocessing import Pool
def run(fn) :
time.sleep(2)
print fn
if __name__ == "__main__" :
startTime = time.time()
testFL = [1,2,3,4,5]
pool = Pool(10)#可以同時跑10個程式
pool.map(run,testFL)
pool.close()
pool.join()
endTime = time.time()
print "time :", endTime - startTime
執行結果:
21
3
4
5
time : 2.51999998093
再次執行結果如下:
1
34
2
5
time : 2.48600006104
結果中為什麼還有空行和沒有折行的資料呢?其實這跟程式排程有關,當有多個程式並行執行時,每個程式得到的時間片時間不一樣,哪個程式接受哪個請求以及執行完成時間都是不定的,所以會出現輸出亂序的情況。那為什麼又會有沒這行和空行的情況呢?因為有可能在執行第一個程式時,剛要列印換行符時,切換到另一個程式,這樣就極有可能兩個數字列印到同一行,並且再次切換回第一個程式時會列印一個換行符,所以就會出現空行的情況。
程式實戰例項
並行處理某個目錄下檔案中的字元個數和行數,存入res.txt檔案中,
每個檔案一行,格式為:filename:lineNumber,charNumber
import os
import time
from multiprocessing import Pool
def getFile(path) :
#獲取目錄下的檔案list
fileList = []
for root, dirs, files in list(os.walk(path)) :
for i in files :
if i.endswith('.txt') or i.endswith('.10w') :
fileList.append(root + "\\" + i)
return fileList
def operFile(filePath) :
#統計每個檔案中行數和字元數,並返回
filePath = filePath
fp = open(filePath)
content = fp.readlines()
fp.close()
lines = len(content)
alphaNum = 0
for i in content :
alphaNum += len(i.strip('\n'))
return lines,alphaNum,filePath
def out(list1, writeFilePath) :
#將統計結果寫入結果檔案中
fileLines = 0
charNum = 0
fp = open(writeFilePath,'a')
for i in list1 :
fp.write(i[2] + " 行數:"+ str(i[0]) + " 字元數:"+str(i[1]) + "\n")
fileLines += i[0]
charNum += i[1]
fp.close()
print fileLines, charNum
if __name__ == "__main__":
#建立多個程式去統計目錄中所有檔案的行數和字元數
startTime = time.time()
filePath = "C:\\wcx\\a"
fileList = getFile(filePath)
pool = Pool(5)
resultList =pool.map(operFile, fileList)
pool.close()
pool.join()
writeFilePath = "c:\\wcx\\res.txt"
print resultList
out(resultList, writeFilePath)
endTime = time.time()
print "used time is ", endTime - startTime
執行結果:
耗時不到1秒,可見多程式併發執行速度是很快的。
相關文章
- python 多程式詳解Python
- python 多繼承詳解Python繼承
- python 多型 協議詳解Python多型協議
- 【多程式】Linux中fork()函式詳解|多程式Linux函式
- 詳解Python物件導向程式設計之類、例項、方法Python物件程式設計
- 詳解Python中的程式Python
- 詳細介紹Python類的繼承與多型Python繼承多型
- 元類詳解
- 多執行緒系列(十五) -常用併發工具類詳解執行緒
- 多執行緒系列(十六) -常用併發原子類詳解執行緒
- python超程式設計詳解(3)Python程式設計
- python超程式設計詳解(4)Python程式設計
- python超程式設計詳解(2)Python程式設計
- 〈詳解〉Python3呼叫C程式PythonC程式
- UML類圖詳解
- LinkedList類詳解
- 詳解Unsafe類
- Java Class類詳解Java
- 詳解 JavaScript 的類JavaScript
- 詳解javascript的類JavaScript
- [Java]File類詳解Java
- [Java]RandomAccessFile類詳解JavarandomMac
- Java集合類詳解Java
- 機器學習_K近鄰Python程式碼詳解機器學習Python
- python Gui程式設計工具詳解:beewarePythonGUI程式設計
- Python程式、執行緒、協程詳解Python執行緒
- Python多程式Python
- Python - 關於類(self/cls) 以及 多程式通訊的思考Python
- Python關於反射和類的特殊成員方法詳解Python反射
- 抽象類及介面詳解抽象
- dart類詳細講解Dart
- Java內部類詳解Java
- Java 內部類詳解Java
- CSS偽類使用詳解CSS
- CSS偽類的詳解CSS
- Atomic 原子類詳解
- python:python的多程式Python
- python函數語言程式設計詳解Python函數程式設計