最近的一個項目中在使用grpc時遇到一個問題,因爲client端可多達200,每一個端口每10s向grpc server發送一次請求,server端接受client的請求後根據request信息更新數據庫,再將數據庫和配置文件的某些數據封裝後返回給client。原代碼的性能是0.26s/request,遠遠達不到所需性能,其中數據庫更新操做耗時達到80%,其中一個優化點就是將數據庫更新操做放在獨立的線程中。
在次以前沒有使用過線程編碼,學以至用後本着加深理解的想法,將這個過程記錄下來,這裏先記下用於線程間通訊的隊列Queue的相關知識。數據庫
Python2中隊列庫名稱爲Queue,Python3中已更名爲queue,項目使用Python2.7.5版本,天然是使用Queue。
Queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(後入先出)隊列LifoQueue,和優先級隊列PriorityQueue。這些隊列都實現了鎖原語,可在多線程通訊中直接使用。安全
Queue模塊定義瞭如下類及異常,在隊列類中,maxsize
限制可入隊列數據的數量,值小於等於0時表明不限制:多線程
Queue.Queue(maxsize=0)
FIFO隊列Queue.LifoQueue(maxsize=0)
LIFO隊列Queue.PriorityQueue(maxsize=0)
優先級隊列Queue.Empty
TODO
Queue.Full
Queue(Queue、LifoQueue、PriorityQueue)對象提供如下方法:性能
Queue.qsize()
Queue.empty()
Queue.full()
Queue.put(item[, block[, timeout]])
Queue.put_nowait(item)
put(item, False)
Queue.get([block[, timeout]])
Queue.get_nowait()
get(item, False)
Queue.task_done()
Queue.join()
UpdateThread
是單一消費者進程,獲取FIFO隊列中的數據處理,GrpcThread
是multi生產者線程,須要對往隊列中丟數據這個操做加鎖保證數據前後順序。學習
import threading import Queue import time q = Queue.Queue() q_lock = threading.Lock() class UpdateThread(threading.Thread): def __init__(self): super(self.__class__, self).__init__() self.setName(self.__class__.__name__) self._setName = self.setName @staticmethod def update_stat(): global q while not q.empty(): stat = q.get() print 'Update stat (%s) in db' % stat def run(self): while True: self.update_stat() time.sleep(0.1) class GrpcThread(threading.Thread): def compose_stat(self, stat): global q q_lock.acquire() q.put('%d: %s' % (stat, self.name)) q_lock.release() return def run(self): for i in range(10): self.compose_stat(i) time.sleep(0.1) def launch_update_thread(): UpdateThread().start() if __name__ == '__main__': launch_update_thread() thread1 = GrpcThread() thread2 = GrpcThread() thread1.start() thread2.start()