這篇博文主要講下筆者在工作中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
<code>#!/usr/local/python27/bin/python2.7</code>
<code>from</code> <code>multiprocessing </code><code>import</code> <code>Process,Pool</code>
<code>import</code> <code>os,time,random,sys</code>
<code>import</code> <code>urllib</code>
<code># 檔案下載下傳函數</code>
<code>def</code> <code>filedown(url,</code><code>file</code><code>):</code>
<code> </code><code>urllib.urlretrieve(url,</code><code>file</code><code>)</code>
<code>if</code> <code>__name__ </code><code>=</code><code>=</code> <code>'__main__'</code><code>:</code>
<code> </code><code>p </code><code>=</code> <code>Pool(</code><code>100</code><code>)</code>
<code> </code><code>count </code><code>=</code> <code>0</code>
<code> </code><code># 打開存有url的檔案</code>
<code> </code><code>f </code><code>=</code> <code>open</code><code>(</code><code>'11.csv'</code><code>,</code><code>'r'</code><code>)</code>
<code> </code><code>while</code> <code>True</code><code>:</code>
<code> </code><code>count </code><code>+</code><code>=</code> <code>1</code>
<code> </code><code># 按行讀取</code>
<code> </code><code>url1 </code><code>=</code> <code>f.readline()</code>
<code> </code><code># 當檔案讀取完畢時,跳出循環</code>
<code> </code><code>if</code> <code>url1 </code><code>=</code><code>=</code> <code>'':</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>url </code><code>=</code> <code>url1.strip()</code>
<code> </code><code>file</code> <code>=</code> <code>(</code><code>'/root/tuchao/d2/work/strfile/'</code><code>+</code><code>url.split(</code><code>'/'</code><code>)[</code><code>4</code><code>])</code>
<code> </code><code>print</code><code>(count)</code>
<code> </code><code># 使用異步多程序的方式,啟動子程序,并将功能函數和參數傳入.</code>
<code> </code><code># 注意: 這裡的 args 必須傳參數清單,就算是一個參數,也得寫逗号結尾。</code>
<code> </code><code>p.apply_async(filedown, args</code><code>=</code><code>(url,</code><code>file</code><code>,))</code>
<code> </code><code>p.close()</code>
<code> </code><code>p.join()</code>
實戰二、批量文本處理。
讀取一個目錄下的每個檔案,過濾掉檔案中的數字和中文,把每個英語單詞提取出來寫入 Mongodb。
使用多程序處理
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<code>import</code> <code>re</code>
<code>import</code> <code>sys</code>
<code>import</code> <code>os</code>
<code>import</code> <code>pymongo</code>
<code>import</code> <code>time</code>
<code># Mongodb 連接配接,驗證身份</code>
<code>conn </code><code>=</code> <code>pymongo.MongoClient(</code><code>'localhost'</code><code>,</code><code>27017</code><code>)</code>
<code>conn.words.authenticate(</code><code>'words_user'</code><code>,</code><code>'woiu32k32x01'</code><code>)</code>
<code>db </code><code>=</code> <code>conn.words</code>
<code># 單詞處理函數</code>
<code>def</code> <code>wordsevent(filename,mongo_insert):</code>
<code> </code><code>with </code><code>open</code><code>(filename) as f:</code>
<code> </code><code>wordsall</code><code>=</code><code>[]</code>
<code> </code><code>for</code> <code>line </code><code>in</code> <code>f:</code>
<code> </code><code># 把目前行轉為小寫後,判斷裡面是否包含小寫字母。 有,表示這行是英文行,則做單詞提取。 沒有,表示目前行是數字或者是中文,不做處理,continue 進入下一次循環。</code>
<code> </code><code>if</code> <code>line.lower().islower():</code>
<code> </code>
<code> </code><code># 單詞提取 re.findall 多重比對。(r'(\w|\')+)' 表示比對字母或者單引号出現一次或多次。這樣會出現一個問題,提取出來的單詞都會拆分成一個一個字母,因為正則會安裝括号裡面的規則去提取,\w 按字母比對的,是以會提取字母。 </code>
<code> </code><code># 是以才要這樣寫 (r'((?:\w|\')+)' 這裡 ?: 寫在括号的裡面,表示此括号的規則隻做比對,而不提取内容。 外面還有一層括号,是以正則将會提取外面這層括号比對的内容。 那就是一個個的單詞了。 </code>
<code> </code><code># 在正則中一對括号表示一組。 </code>
<code> </code><code>wordslist </code><code>=</code> <code>re.findall(r</code><code>'((?:\w|\')+)'</code><code>,line)</code>
<code> </code><code># 清單合并,把多個list合并到一個。</code>
<code> </code><code>wordsall.extend(wordslist)</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>continue</code>
<code> </code><code># 把list轉成集合去重,因為集合中的元素是 确定性、無序性、互異性 </code>
<code> </code><code>s1</code><code>=</code><code>set</code><code>(wordsall)</code>
<code> </code><code>if</code> <code>len</code><code>(s1) </code><code>=</code><code>=</code> <code>0</code><code>:</code>
<code> </code><code>pass</code>
<code> </code><code>else</code><code>:</code>
<code> </code><code>mongo_insert(s1)</code>
<code>def</code> <code>mongo_insert(x):</code>
<code> </code><code>db.test2.insert_many([{</code><code>"word"</code><code>:i} </code><code>for</code> <code>i </code><code>in</code> <code>x])</code>
<code> </code><code>fileall</code><code>=</code><code>os.listdir(</code><code>'strfile'</code><code>)</code>
<code> </code><code>p </code><code>=</code> <code>Pool(</code><code>10</code><code>)</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>fileall:</code>
<code> </code><code>filename </code><code>=</code> <code>(</code><code>'/root/tuchao/d2/work/strfile/%s'</code> <code>%</code> <code>i)</code>
<code> </code><code>print</code><code>(count,filename)</code>
<code> </code><code># 啟動異步多程序</code>
<code> </code><code>p.apply_async(wordsevent,args</code><code>=</code><code>(filename,mongo_insert,))</code>
回調函數
什麼是回調函數? (第一次聽說回調函數的同學,請認真看下補課)
程式設計分為兩類:系統程式設計(system programming)和應用程式設計(application programming)。所謂系統程式設計,簡單來說,就是編寫庫;而應用程式設計就是利用寫好的各種庫來編寫具某種功用的程式,也就是應用。系統程式員會給自己寫的庫留下一些接口,即API(application programming interface,應用程式設計接口),以供應用程式員使用。是以在抽象層的圖示裡,庫位于應用的底下。
當程式跑起來時,一般情況下,應用程式(application program)會時常通過API調用庫裡所預先備好的函數。但是有些庫函數(library function)卻要求應用先傳給它一個函數,好在合适的時候調用,以完成目标任務。這個被傳入的、後又被調用的函數就稱為回調函數(callback function)。
打個比方,有一家旅館提供叫醒服務,但是要求旅客自己決定叫醒的方法。可以是打客房電話,也可以是派服務員去敲門,睡得死怕耽誤事的,還可以要求往自己頭上澆盆水。這裡,“叫醒”這個行為是旅館提供的,相當于庫函數,但是叫醒的方式是由旅客決定并告訴旅館的,也就是回調函數。而旅客告訴旅館怎麼叫醒自己的動作,也就是把回調函數傳入庫函數的動作,稱為登記回調函數(to register a callback function)
<a href="http://s5.51cto.com/wyfs02/M00/8C/35/wKiom1hk_maDzDp7AACLDhIdbUo502.jpg" target="_blank"></a>
可以看到,回調函數通常和應用處于同一抽象層(因為傳入什麼樣的回調函數是在應用級别決定的)。而回調就成了一個高層調用底層,底層再回過頭來調用高層的過程。
回調機制的優勢
從上面的例子可以看出,回調機制提供了非常大的靈活性。請注意,從現在開始,我們把圖中的庫函數改稱為中間函數了,這是因為回調并不僅僅用在應用和庫之間。任何時候,隻要想獲得類似于上面情況的靈活性,都可以利用回調。
這種靈活性是怎麼實作的呢?乍看起來,回調似乎隻是函數間的調用,但仔細一琢磨,可以發現兩者之間的一個關鍵的不同:在回調中,我們利用某種方式,把回調函數像參數一樣傳入中間函數。可以這麼了解,在傳入一個回調函數之前,中間函數是不完整的。換句話說,程式可以在運作時,通過登記不同的回調函數,來決定、改變中間函數的行為。這就比簡單的函數調用要靈活太多了。
作者:橋頭堡
連結:https://www.zhihu.com/question/19801131/answer/27459821
來源:知乎
是不是還沒太明白,隻是大概有點了解咋回事了。 别急看下面代碼。
一個簡單的回調函數的程式
<code>def</code> <code>a(i):</code>
<code> </code><code>print</code><code>(</code><code>"this is a start"</code><code>)</code>
<code> </code><code>print</code><code>(i)</code>
<code> </code><code>print</code><code>(</code><code>"this is a stop"</code><code>)</code>
<code>def</code> <code>b(func):</code>
<code> </code><code>print</code><code>(</code><code>"this is b start"</code><code>)</code>
<code> </code><code>for</code> <code>i </code><code>in</code> <code>range</code><code>(</code><code>10</code><code>):</code>
<code> </code><code>func(i)</code>
<code> </code><code>print</code><code>(</code><code>"this is b stop"</code><code>)</code>
<code> </code><code>b(a)</code>
輸出如下:
<a href="http://s3.51cto.com/wyfs02/M02/8C/35/wKiom1hlAaTDVXcEAAAZN9y3Al4183.png" target="_blank"></a>
一個使用多程序結合回調函數的示例程式
<code>def</code> <code>a(x):</code>
<code> </code><code>print</code><code>(x)</code>
<code>def</code> <code>b(num):</code>
<code> </code><code>return</code><code>(num)</code>
<code> </code><code>p </code><code>=</code> <code>Pool(</code><code>5</code><code>)</code>
<code> </code><code># 這裡表示,當b函數執行完成之後就會調用a函數,并且把b函數的傳回值傳給a函數。</code>
<code> </code><code>p.apply_async(b, args</code><code>=</code><code>(i,), callback</code><code>=</code><code>a)</code>
<a href="http://s5.51cto.com/wyfs02/M00/8C/32/wKioL1hlAniRwH06AAAZYE92Po8897.png" target="_blank"></a>
多程序結合回調函數寫檔案的示例程式
<a href="http://blog.csdn.net/Q_AN1314/article/details/51923022" target="_blank">http://blog.csdn.net/Q_AN1314/article/details/51923022</a>
相信現在差不多明白了吧,還不明白的再傳回上面看看理論。 了解也不是難事了。
Pymongo 相關文檔
http://www.cnblogs.com/lomper/p/4776452.html?utm_source=tuicool&utm_medium=referral
http://api.mongodb.com/python/current/
本文轉自qw87112 51CTO部落格,原文連結:http://blog.51cto.com/tchuairen/1887468