python多線程并發(fā)threading模塊

最近開發(fā)一個獲取所有集群從讀寫實例的接口偿凭,運行接口發(fā)現(xiàn)返回數(shù)據(jù)時間長杠巡,達(dá)到了9秒多,實在是太慢了埃撵!那么慢在哪里呢赵颅?

review代碼,發(fā)現(xiàn)是因為需要讀取二十多個不同的數(shù)據(jù)庫查詢結(jié)果暂刘,這些數(shù)據(jù)庫分布在二十多臺不同的物理機(jī)饺谬,代碼采用for循環(huán)依次讀取這些數(shù)據(jù)庫,從而產(chǎn)生耗時嚴(yán)重的情況.

模擬for循環(huán)依次讀取數(shù)據(jù)庫腳本如下:

#!/usr/bin/python
# encoding=utf-8

import os
import mysql.connector

ossdb_dict = {'上海A':'xxx.xxx.xxx.xxx:3306','上海B':'xxx.xxx.xxx.xxx:3306','上海C':'xxx.xxx.xxx.xxx:3306','北京A':'xxx.xxx.xxx.xxx:3306','北京B':'xxx.xxx.xxx.xxx:3306','北美A':'xxx.xxx.xxx.xxx:3306','天津A':'xxx.xxx.xxx.xxx:3306','天津B':'xxx.xxx.xxx.xxx:3306','廣州A':'xxx.xxx.xxx.xxx:3306','廣州B':'xxx.xxx.xxx.xxx:3306','廣州C':'xxx.xxx.xxx.xxx:3306','廣州D':'xxx.xxx.xxx.xxx:3306','德國A':'xxx.xxx.xxx.xxx:3306','成都A':'xxx.xxx.xxx.xxx:3306','新加坡A':'xxx.xxx.xxx.xxx:3306','深圳A':'xxx.xxx.xxx.xxx:3306','深圳B':'xxx.xxx.xxx.xxx:3306','美國A':'xxx.xxx.xxx.xxx:3306','重慶A':'xxx.xxx.xxx.xxx:3306','香港A':'xxx.xxx.xxx.xxx:3306','韓國A':'xxx.xxx.xxx.xxx:3306','廣州E':'xxx.xxx.xxx.xxx:3306'}

cluster_dict = {'上海A':49,'上海B':61,'上海C':63,'北京A':204,'北京B':206,'北美A':59,'天津A':64,'天津B':70,'廣州A':73,'廣州B':22,'廣州C':60,'廣州永順':D,'德國A':202,'成都A':201,'新加坡A':71,'深圳A':74,'深圳B':81,'美國A':79,'重慶A':205,'香港A':52,'韓國A':207,'廣州E':76}

slave_rw_sql = """select tb_mysql_pair.instance_name,tb_mysql_pair.app_name,tb_mysql_pair.master_port,tb_mysql_pair.slave_port,tb_device_pair.master_ip,tb_device_pair.slave_ip from tb_mysql_pair,tb_device_pair where tb_mysql_pair.status=19 and tb_mysql_pair.device_pair_id=tb_device_pair.pair_id;"""

db_user  = 'xxx'
db_pass = 'xxx'
access_db = 'xxx'   

def execDB(ossdb_dict,cluster_dict,db_user,db_pass,access_db,slave_rw_sql):
         
    cluster_ids  = []
    for key in cluster_dict:
        id   = cluster_dict[key] 
        cluster_ids.append(id)

    ossdb_list = [] 
    for cluster_id in cluster_ids:
        cluster_name = cluster_dict.keys()[cluster_dict.values().index(cluster_id)]
        ossdb  = ossdb_dict[cluster_name]

        ossdb_list.append(ossdb)

    #for循環(huán)一個一個讀取數(shù)據(jù)庫鸳惯,是單線程的商蕴,所以會比較慢
    for ossdb in ossdb_list:
        cluster_name = ossdb_dict.keys()[ossdb_dict.values().index(ossdb)]
        db_host  = ossdb.split(':',1)[0]
        db_port   = ossdb.split(':',1)[1]

        conn = mysql.connector.connect(
            user  = db_user,
            password = db_pass,
            host  = db_host,
            port   = db_port,
            database = access_db)

        cur = conn.cursor()
        cur.execute(slave_rw_sql)
        slave_rw_results = cur.fetchall()


if __name__=='__main__':
    execDB(ossdb_dict,cluster_dict,db_user,db_pass,access_db,slave_rw_sql)

實際執(zhí)行腳本,耗時情況:
time python 3.py

real 0m9.444s
user 0m0.060s
sys 0m0.016s

跑完腳本需要0m9.444s芝发,很顯然耗時是在for循環(huán)依次查詢數(shù)據(jù)庫產(chǎn)生的耗時.

是否有辦法提高讀取數(shù)據(jù)庫的效率绪商,消除耗時呢?答案是肯定的辅鲸!

python的標(biāo)準(zhǔn)庫提供了并發(fā)執(zhí)行的多線程模塊thread和threading格郁,thread是低級模塊,而threading是高級模塊独悴,對thread進(jìn)行了封裝例书。在絕大多數(shù)情況下,我們只需要使用threading這個高級模塊.

在python中實現(xiàn)多線程有兩種方式刻炒,一種就是函數(shù)形式决采,通過將需要執(zhí)行的方法傳入,然后創(chuàng)建多線程實例坟奥;另一種就是創(chuàng)建一個類树瞭,并且繼承threading.Thread類來實現(xiàn). 這里我只講第一種方式拇厢,比較容易理解一些.

注:
什么是多線程呢?顧名思義晒喷,多線程就是在同一個進(jìn)程的情況下拉起來多個線程孝偎,進(jìn)程和線程之間的關(guān)系,就好比是工廠和工人之間的關(guān)系凉敲。工廠是一個衣盾,但是工人有多個,多人干活自然就可以提高生產(chǎn)效率爷抓。

來看看多線程并發(fā)執(zhí)行的腳本:

#!/usr/bin/python
# encoding=utf-8


import os
import threading  #引入threading多線程模塊
import mysql.connector

ossdb_dict = {'上海A':'xxx.xxx.xxx.xxx:3306','上海B':'xxx.xxx.xxx.xxx:3306','上海C':'xxx.xxx.xxx.xxx:3306','北京A':'xxx.xxx.xxx.xxx:3306','北京B':'xxx.xxx.xxx.xxx:3306','北美A':'xxx.xxx.xxx.xxx:3306','天津A':'xxx.xxx.xxx.xxx:3306','天津B':'xxx.xxx.xxx.xxx:3306','廣州A':'xxx.xxx.xxx.xxx:3306','廣州B':'xxx.xxx.xxx.xxx:3306','廣州C':'xxx.xxx.xxx.xxx:3306','廣州D':'xxx.xxx.xxx.xxx:3306','德國A':'xxx.xxx.xxx.xxx:3306','成都A':'xxx.xxx.xxx.xxx:3306','新加坡A':'xxx.xxx.xxx.xxx:3306','深圳A':'xxx.xxx.xxx.xxx:3306','深圳B':'xxx.xxx.xxx.xxx:3306','美國A':'xxx.xxx.xxx.xxx:3306','重慶A':'xxx.xxx.xxx.xxx:3306','香港A':'xxx.xxx.xxx.xxx:3306','韓國A':'xxx.xxx.xxx.xxx:3306','廣州E':'xxx.xxx.xxx.xxx:3306'}

cluster_dict = {'上海A':49,'上海B':61,'上海C':63,'北京A':204,'北京B':206,'北美A':59,'天津A':64,'天津B':70,'廣州A':73,'廣州B':22,'廣州C':60,'廣州永順':D,'德國A':202,'成都A':201,'新加坡A':71,'深圳A':74,'深圳B':81,'美國A':79,'重慶A':205,'香港A':52,'韓國A':207,'廣州E':76}

slave_rw_sql = """select tb_mysql_pair.instance_name,tb_mysql_pair.app_name,tb_mysql_pair.master_port,tb_mysql_pair.slave_port,tb_device_pair.master_ip,tb_device_pair.slave_ip from tb_mysql_pair,tb_device_pair where tb_mysql_pair.status=19 and tb_mysql_pair.device_pair_id=tb_device_pair.pair_id;"""

db_user  = 'xxx'
db_pass  = 'xxx'
access_db  = 'xxx'   

def execDB(ossdb,ossdb_dict,db_user,db_pass,access_db,slave_rw_sql):
    cluster_name = ossdb_dict.keys()[ossdb_dict.values().index(ossdb)]
    db_host   = ossdb.split(':',1)[0]
    db_port    = ossdb.split(':',1)[1]
    
    conn = mysql.connector.connect(
        user  = db_user,
        password = db_pass,
        host   = db_host,
        port    = db_port,
        database = access_db)
        
    cur = conn.cursor()
    cur.execute(slave_rw_sql)
    slave_rw_results = cur.fetchall()


#定義多線程執(zhí)行的函數(shù)multithread  
def multithread(ossdb_dict,cluster_dict,db_user,db_pass,access_db,slave_rw_sql):
    cluster_ids  = []
    for key in cluster_dict:
        id  = cluster_dict[key]
        cluster_ids.append(id)
        
    ossdb_list = []
    for cluster_id in cluster_ids:
        cluster_name = cluster_dict.keys()[cluster_dict.values().index(cluster_id)]
        ossdb   = ossdb_dict[cluster_name]
        
        ossdb_list.append(ossdb)
    
    #定義一個列表threads势决,存儲要啟動多線程的實例
    threads = []
    
    #循環(huán)讀取多個ossdb,也就是啟動了多個線程去查詢DB啦~
    for ossdb in ossdb_list:
           #target表示實際要執(zhí)行讀取數(shù)據(jù)庫的函數(shù)废赞,multithread函數(shù)調(diào)用execDB函數(shù)徽龟,往execDB函數(shù)傳參.
        t   = threading.Thread(target=execDB,args=(ossdb,ossdb_dict,db_user,db_pass,access_db,slave_rw_sql,))  
        threads.append(t)   #把要啟動多線程的實例,追加到列表threads
        

    #把threads列表中的實例遍歷出來后唉地,調(diào)用start()方法啟動多線程据悔,就會有多個線程并發(fā)去讀取數(shù)據(jù)庫
    for thr in threads:
        thr.start()
    
    for thr in threads:
        #isAlive()可以返回true或者false,用來判斷此時是否還有沒有執(zhí)行完的線程,如果還有未執(zhí)行完的線程就讓主線程等待線程執(zhí)行結(jié)束之后耘沼,主線程再來結(jié)束.
        if thr.isAlive():
            thr.join()
    
if __name__=='__main__':
    multithread(ossdb_dict,cluster_dict,db_user,db_pass,access_db,slave_rw_sql)

上述腳本遍歷了兩次threads列表极颓,最后一次遍歷的目的是為了查看還有沒有沒有執(zhí)行完成的子線程,只要還有子線程是活的群嗤,沒有退出菠隆,就通過join()方法強(qiáng)制程序不可以讓主線程退出,只有等所有子線程執(zhí)行完成退出后狂秘,才能讓主線程退出.

來看看采用多線程并發(fā)之后骇径,實際執(zhí)行腳本耗時:
time python 1.py
real 0m1.927s
user 0m0.064s
sys 0m0.012s

可以看到耗時0m1.927s,效率已經(jīng)提升了好幾倍者春,這個耗時在可接受范圍.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末破衔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钱烟,更是在濱河造成了極大的恐慌晰筛,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拴袭,死亡現(xiàn)場離奇詭異读第,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拥刻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門怜瞒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人般哼,你說我怎么就攤上這事盼砍〕韭穑” “怎么了逝她?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵浇坐,是天一觀的道長。 經(jīng)常有香客問我黔宛,道長近刘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任臀晃,我火速辦了婚禮觉渴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘徽惋。我一直安慰自己案淋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布险绘。 她就那樣靜靜地躺著踢京,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宦棺。 梳的紋絲不亂的頭發(fā)上瓣距,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機(jī)與錄音代咸,去河邊找鬼蹈丸。 笑死,一個胖子當(dāng)著我的面吹牛呐芥,可吹牛的內(nèi)容都是我干的逻杖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼思瘟,長吁一口氣:“原來是場噩夢啊……” “哼荸百!你這毒婦竟也來了屡久?” 一聲冷哼從身側(cè)響起孤页,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎裸扶,沒想到半個月后铡买,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體更鲁,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年奇钞,在試婚紗的時候發(fā)現(xiàn)自己被綠了澡为。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡景埃,死狀恐怖媒至,靈堂內(nèi)的尸體忽然破棺而出顶别,到底是詐尸還是另有隱情,我是刑警寧澤拒啰,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布驯绎,位于F島的核電站,受9級特大地震影響谋旦,放射性物質(zhì)發(fā)生泄漏剩失。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一册着、第九天 我趴在偏房一處隱蔽的房頂上張望拴孤。 院中可真熱鬧,春花似錦甲捏、人聲如沸演熟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芒粹。三九已至,卻和暖如春免猾,著一層夾襖步出監(jiān)牢的瞬間是辕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工猎提, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留获三,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓锨苏,卻偏偏與公主長得像疙教,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伞租,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容