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

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


多進程實戰


實戰一、批量文件下載

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


#!/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__':
    p = Pool(100)
    count = 0
    # 打開存有url的文件
    f = 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。

使用多進程處理


#!/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 i in x])


if __name__ == '__main__':
    fileall=os.listdir('strfile')
    p = Pool(10)
    count = 0
    for i 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()


實戰三、讀取 word 文檔  

讀取 word 文檔,按每段取出內容,分析整篇文檔中去重後的單詞數量


Python可以利用python-docx模塊處理word文檔,處理方式是面向對象的。也就是說python-docx模塊會把word文檔,文檔中的段落、文本、字體等都看做對象,對對象進行處理就是對word文檔的內容處理。


1、瞭解下 python-docx 模塊的幾個概念

  • Document對象,表示一個word文檔。

  • Paragraph對象,表示word文檔中的一個段落

  • Paragraph對象的text屬性,表示段落中的文本內容。


2、模塊的安裝和導入

pip install python-docx

# 導入模塊
import docx

3、實例代碼

import docx
import re

# 獲取文檔對象
file = docx.Document('C:\\Users\\tuchao\\Desktop\\The little princess.docx')

#統計每個章節的去重單詞數
for i in range(len(file.paragraphs)):
    # 循環文檔的段落數,取出每一個段落的內容
    data = file.paragraphs[i].text
    data_list = re.split('[ ,]',data)

    if len(data_list) >= 2:
        if data_list[0] == 'Chapter':
            print(data)
        else:
            words_count = len(set(data_list))
            print(words_count)


# #統計整篇文章的去重單詞數
count_list = []
for i in range(len(file.paragraphs)):
    data = file.paragraphs[i].text
    data_list = re.split('[ ,]',data)
    if len(data_list) > 2:
        count_list.extend(data_list)

#打印詞表
print(set(count_list))
#打印單詞數
print(len(set(count_list)))


# 更省內存的寫法
count_set = set()
for i in range(len(file.paragraphs)):
    data = file.paragraphs[i].text
    data_list = re.split('[ ,]',data)
    if len(data_list) > 2:
        for word in data_list:
            count_set.add(word)
#打印詞表
print(count_set)
#打印單詞數
print(len(set(count_set)))


TXT 文本的處理代碼

file = open('C:\\Users\\tuchao\\Desktop\\The Adventures of Pinocchio - Carlo Collodi.txt','r')

a = re.findall(r'((?:\w|\')+)',file.read())
print(len(set(a)))



回調函數


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


編程分爲兩類:系統編程(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
來源:知乎


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


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

#!/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 i in range(10):
        func(i)
    print("this is b stop")

if __name__ == '__main__':
    b(a)

輸出如下:

wKiom1hlAaTDVXcEAAAZN9y3Al4183.png


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

#!/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__':
    p = Pool(5)
    for i 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


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


Pymongo 相關文檔

http://www.cnblogs.com/lomper/p/4776452.html?utm_source=tuicool&utm_medium=referral

http://api.mongodb.com/python/current/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章