Python線程編程—同步隊列

來源:互聯網
上載者:User

我們經常會採用生產者/消費者關係的兩個線程來處理一個共用緩衝區的資料。例如一個生產者線程接受使用者資料放入一個共用緩衝區裡,等待一個消費者線程對資料取出處理。但是如果緩衝區的太小而生產者和消費者兩個非同步線程的速度不同時,容易出現一個線程等待另一個情況。為了儘可能的縮短共用資源並以相同速度工作的各線程的等待時間,我們可以使用一個“隊列”來提供額外的緩衝區。

建立一個“隊列”對象

import Queue
myqueue = Queue.Queue(maxsize = 10)

Queue.Queue類即是一個隊列的同步實現。隊列長度可為無限或者有限。可通過Queue的建構函式的選擇性參數maxsize來設定隊列長度。如果maxsize小於1就表示隊列長度無限。

將一個值放入隊列中

myqueue.put(10)

調用隊列對象的put()方法在隊尾插入一個項目。put()有兩個參數,第一個item為必需的,為插入項目的值;第二個block為選擇性參數,預設為1。如果隊列當前為空白且block為1,put()方法就使調用線程暫停,直到空出一個資料單元。如果block為0,put方法將引發Full異常。

將一個值從隊列中取出

myqueue.get()

調用隊列對象的get()方法從隊頭刪除並返回一個項目。選擇性參數為block,預設為1。如果隊列為空白且block為1,get()就使調用線程暫停,直至有項目可用。如果block為0,隊列將引發Empty異常。

我們用一個例子來展示如何使用Queue

#!/usr/bin/env python
import Queue
import threading
import urllib2
import time

hosts = ["http://yahoo.com", "http://google.com.hk", "http://amazon.com",
"http://ibm.com", "http://apple.com"]

queue = Queue.Queue()

class ThreadUrl(threading.Thread):
"""Threaded Url Grab"""
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue

def run(self):
while True:
#grabs host from queue
host = self.queue.get()
#grabs urls of hosts and prints first 1024 bytes of page
url = urllib2.urlopen(host)
print url.read(1024)
#signals to queue job is done
self.queue.task_done()

start = time.time()
def main():
#spawn a pool of threads, and pass them queue instance
for i in range(5):
t = ThreadUrl(queue)
t.setDaemon(True)
t.start()

#populate queue with data
for host in hosts:
queue.put(host)
#wait on the queue until everything has been processed
queue.join()

main()
print "Elapsed Time: %s" % (time.time() - start)

 

在 Python 中使用線程時,這個模式是一種很常見的並且推薦使用的方式。具體工作步驟描述如下:

  1. 建立一個 Queue.Queue() 的執行個體,然後使用資料對它進行填充。
  2. 將經過填充資料的執行個體傳遞給線程類,後者是通過繼承 threading.Thread 的方式建立的。
  3. 產生守護線程池。
  4. 每次從隊列中取出一個項目,並使用該線程中的資料和 run 方法以執行相應的工作。
  5. 在完成這項工作之後,使用 queue.task_done() 函數向任務已經完成的隊列發送一個訊號。
  6. 對隊列執行 join 操作,實際上意味著等到隊列為空白,再退出主程式。

在使用這個模式時需要注意一點:通過將守護線程設定為 true,將允許主線程或者程式僅在守護線程處於活動狀態時才能夠退出。這種方式建立了一種簡單的方式以控製程序流程,因為在退出之前,您可以對隊列執行 join 操作、或者等到隊列為空白。

join()

保持阻塞狀態,直到處理了隊列中的所有項目為止。在將一個項目添加到該隊列時,未完成的任務的總數就會增加。當使用者線程調用 task_done() 以表示檢索了該項目、並完成了所有的工作時,那麼未完成的任務的總數就會減少。當未完成的任務的總數減少到零時,join() 就會結束阻塞狀態。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.