最近開發(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)提升了好幾倍者春,這個耗時在可接受范圍.