Python 多進程實戰 & 回調函數理解與實戰


這篇博文主要講下筆者在工作中Python多進程的實戰運用和回調函數的理解和運用。

 

多進程實戰

 

實戰一、批量文件下載

從一個文件中按行讀取 url ,根據 url 下載文件到指定位置,用多進程實現。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/local/python27/bin/python2.7
from  multiprocessing  import  Process,Pool
import  os,time,random,sys
import  urllib
 
# 文件下載函數
def  filedown(url, file ):
     urllib.urlretrieve(url, file )
 
 
 
if  __name__  = =  '__main__' :
     =  Pool( 100 )
     count  =  0
     # 打開存有url的文件
     =  open ( '11.csv' , 'r' )
     while  True :
         count  + =  1
         # 按行讀取
         url1  =  f.readline()
         # 當文件讀取完畢時,跳出循環
         if  url1  = =  '':
             break ;
         url  =  url1.strip()
         file  =  ( '/root/tuchao/d2/work/strfile/' + url.split( '/' )[ 4 ])
         print (count)
         # 使用異步多進程的方式,啟動子進程,並將功能函數和參數傳入.
         # 注意: 這里的 args 必須傳參數列表,就算是一個參數,也得寫逗號結尾。
         p.apply_async(filedown, args = (url, file ,))
     p.close()
     p.join()

 

 

實戰二、批量文本處理。  

讀取一個目錄下的每個文件,過濾掉文件中的數字和中文,把每個英語單詞提取出來寫入 Mongodb。

使用多進程處理

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/local/python27/bin/python2.7
import  re
import  sys
import  os
import  pymongo
from  multiprocessing  import  Process,Pool
import  time
 
# Mongodb 連接,驗證身份
conn  =  pymongo.MongoClient( 'localhost' , 27017 )
conn.words.authenticate( 'words_user' , 'woiu32k32x01' )
db  =  conn.words
 
# 單詞處理函數
def  wordsevent(filename,mongo_insert):
     with  open (filename) as f:
         wordsall = []
         for  line  in  f:
         # 把當前行轉為小寫后,判斷里面是否包含小寫字母。 有,表示這行是英文行,則做單詞提取。  沒有,表示當前行是數字或者是中文,不做處理,continue 進入下一次循環。
             if  line.lower().islower():
             
          # 單詞提取 re.findall 多重匹配。(r'(\w|\')+)' 表示匹配字母或者單引號出現一次或多次。這樣會出現一個問題,提取出來的單詞都會拆分成一個一個字母,因為正則會安裝括號里面的規則去提取,\w 按字母匹配的,所以會提取字母。  
          # 所以才要這樣寫 (r'((?:\w|\')+)' 這里 ?: 寫在括號的里面,表示此括號的規則只做匹配,而不提取內容。 外面還有一層括號,所以正則將會提取外面這層括號匹配的內容。 那就是一個個的單詞了。       
          # 在正則中一對括號表示一組。       
                 wordslist  =  re.findall(r '((?:\w|\')+)' ,line)
                 # 列表合並,把多個list合並到一個。
                 wordsall.extend(wordslist)
             else :
                 continue
         # 把list轉成集合去重,因為集合中的元素是 確定性、無序性、互異性    
         s1 = set (wordsall)
         if  len (s1)  = =  0 :
             pass
         else :
             mongo_insert(s1)
 
             
def  mongo_insert(x):
     db.test2.insert_many([{ "word" :i}  for  in  x])
 
 
if  __name__  = =  '__main__' :
     fileall = os.listdir( 'strfile' )
     =  Pool( 10 )
     count  =  0
     for  in  fileall:
         count  + =  1
         filename  =  ( '/root/tuchao/d2/work/strfile/%s'  %  i)
         print (count,filename)
         # 啟動異步多進程
         p.apply_async(wordsevent,args = (filename,mongo_insert,))
     p.close()
     p.join()

 

回調函數

 

什么是回調函數?  (第一次聽說回調函數的同學,請認真看下補課)

 

編程分為兩類:系統編程(system programming)和應用編程(application programming)。所謂系統編程,簡單來說,就是編寫庫;而應用編程就是利用寫好的各種庫來編寫具某種功用的程序,也就是應用。系統程序員會給自己寫的庫留下一些接口,即API(application programming interface,應用編程接口),以供應用程序員使用。所以在抽象層的圖示里,庫位於應用的底下。

當程序跑起來時,一般情況下,應用程序(application program)會時常通過API調用庫里所預先備好的函數。但是有些庫函數(library function)卻要求應用先傳給它一個函數,好在合適的時候調用,以完成目標任務。這個被傳入的、后又被調用的函數就稱為回調函數(callback function)。

打個比方,有一家旅館提供叫醒服務,但是要求旅客自己決定叫醒的方法。可以是打客房電話,也可以是派服務員去敲門,睡得死怕耽誤事的,還可以要求往自己頭上澆盆水。這里,“叫醒”這個行為是旅館提供的,相當於庫函數,但是叫醒的方式是由旅客決定並告訴旅館的,也就是回調函數。而旅客告訴旅館怎么叫醒自己的動作,也就是把回調函數傳入庫函數的動作,稱為登記回調函數(to register a callback function)


wKiom1hk_maDzDp7AACLDhIdbUo502.jpg

 

可以看到,回調函數通常和應用處於同一抽象層(因為傳入什么樣的回調函數是在應用級別決定的)。而回調就成了一個高層調用底層,底層再過頭來調用高層的過程。

回調機制的優勢

從上面的例子可以看出,回調機制提供了非常大的靈活性。請注意,從現在開始,我們把圖中的庫函數改稱為中間函數了,這是因為回調並不僅僅用在應用和庫之間。任何時候,只要想獲得類似於上面情況的靈活性,都可以利用回調。

這種靈活性是怎么實現的呢?乍看起來,回調似乎只是函數間的調用,但仔細一琢磨,可以發現兩者之間的一個關鍵的不同:在回調中,我們利用某種方式,把回調函數像參數一樣傳入中間函數。可以這么理解,在傳入一個回調函數之前,中間函數是不完整的。換句話說,程序可以在運行時,通過登記不同的回調函數,來決定、改變中間函數的行為。這就比簡單的函數調用要靈活太多了。


作者:橋頭堡
鏈接:https://www.zhihu.com/question/19801131/answer/27459821
來源:知乎

 

是不是還沒太明白,只是大概有點了解咋回事了。  別急看下面代碼。

 

一個簡單的回調函數的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/local/python27/bin/python2.7
 
def  a(i):
     print ( "this is a start" )
     print (i)
     print ( "this is a stop" )
 
 
def  b(func):
     print ( "this is b start" )
     for  in  range ( 10 ):
         func(i)
     print ( "this is b stop" )
 
if  __name__  = =  '__main__' :
     b(a)

輸出如下:

wKiom1hlAaTDVXcEAAAZN9y3Al4183.png

 

一個使用多進程結合回調函數的示例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/local/python27/bin/python2.7
from  multiprocessing  import  Process,Pool
 
 
def  a(x):
     print ( "this is a start" )
     print (x)
     print ( "this is a stop" )
 
 
def  b(num):
     return (num)
 
 
if  __name__  = =  '__main__' :
     =  Pool( 5 )
     for  in  range ( 10 ):
     # 這里表示,當b函數執行完成之后就會調用a函數,並且把b函數的返回值傳給a函數。
         p.apply_async(b, args = (i,), callback = a)
     p.close()
     p.join()

輸出如下:

wKioL1hlAniRwH06AAAZYE92Po8897.png

 

多進程結合回調函數寫文件的示例程序

http://blog.csdn.net/Q_AN1314/article/details/51923022

 

相信現在差不多明白了吧,還不明白的再返回上面看看理論。 理解也不是難事了。

轉自別處。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM