摘要:默認值為,指定為時代表可以阻塞,若同時指定,在超時時返回。當消費者線程調用意味著有消費者取得任務并完成任務,未完成的任務數就會減少。當未完成的任務數降到,解除阻塞。
學習契機
最近的一個項目中在使用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()
返回隊列大小,但是不保證qsize() > 0時,get()不會阻塞;也不保證qsize() < maxsize時,put()不會阻塞。
Queue.empty()
返回True時,不保證put()時不會阻塞;返回False時不保證get()不會阻塞。
Queue.full()
返回True時,不保證get()時不會阻塞;返回False時不保證put()不會阻塞。
Queue.put(item[, block[, timeout]])
block默認值為False,指定為True時代表可以阻塞,若同時指定timeout,在超時時返回Full exception。
Queue.put_nowait(item)
等同put(item, False)
Queue.get([block[, timeout]])
Queue.get_nowait()
等同get(item, False)
Queue.task_done()
消費者線程調用。調用get()后,可調用task_done()告訴隊列該任務已經處理完畢。
如果當前一個join()正在阻塞,它將在隊列中的所有任務都處理完時恢復執行(即每一個由put()調用入隊的任務都有一個對應的task_done()調用)。
Queue.join()
阻塞調用線程,直到隊列中的所有任務被處理掉。
只要有數據被加入隊列,未完成的任務數就會增加。當消費者線程調用task_done()(意味著有消費者取得任務并完成任務),未完成的任務數就會減少。當未完成的任務數降到0,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()
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44586.html
摘要:在生產者與消費者之間的緩沖區稱之為倉庫。生產者負責往倉庫運輸商品,而消費者負責從倉庫里取出商品,這就構成了生產者消費者模式。中的多線程編程在實現生產者消費者模式之前,我們先學習下中的多線程編程。 什么是生產者消費者模式 在軟件開發的過程中,經常碰到這樣的場景:某些模塊負責生產數據,這些數據由其他模塊來負責處理(此處的模塊可能是:函數、線程、進程等)。產生數據的模塊稱為生產者,而處理數據...
摘要:介紹今天花了近乎一天的時間研究關于多線程的問題,查看了大量源碼自己也實踐了一個生產消費者模型,所以把一天的收獲總結一下。提供了兩個模塊和來支持的多線程操作。使用來阻塞線程。 介紹 今天花了近乎一天的時間研究python關于多線程的問題,查看了大量源碼 自己也實踐了一個生產消費者模型,所以把一天的收獲總結一下。 由于GIL(Global Interpreter Lock)鎖的關系,純的p...
摘要:分布式進程在和中,應當優選,因為更穩定,而且,可以分布到多臺機器上,而最多只能分布到同一臺機器的多個上。由于模塊封裝很好,不必了解網絡通信的細節,就可以很容易地編寫分布式多進程程序。 分布式進程 在Thread和Process中,應當優選Process,因為Process更穩定,而且,Process可以分布到多臺機器上,而Thread最多只能分布到同一臺機器的多個CPU上。 Pytho...
摘要:批評的人通常都會說的多線程編程太困難了,眾所周知的全局解釋器鎖,或稱使得多個線程的代碼無法同時運行。多線程起步首先讓我們來創建一個名為的模塊。多進程可能比多線程更易使用,但需要消耗更大的內存。 批評 Python 的人通常都會說 Python 的多線程編程太困難了,眾所周知的全局解釋器鎖(Global Interpreter Lock,或稱 GIL)使得多個線程的 Python 代碼無...
閱讀 3843·2021-09-27 13:56
閱讀 885·2021-09-08 09:36
閱讀 771·2019-08-30 15:54
閱讀 615·2019-08-29 17:29
閱讀 935·2019-08-29 17:21
閱讀 1692·2019-08-29 16:59
閱讀 2764·2019-08-29 13:03
閱讀 2970·2019-08-29 12:47