1.隊(duì)列是先進(jìn)先出,列表可以讀取某個指定數(shù)據(jù)
創(chuàng)新互聯(lián)專注骨干網(wǎng)絡(luò)服務(wù)器租用10多年,服務(wù)更有保障!服務(wù)器租用,四川綿陽服務(wù)器托管 成都服務(wù)器租用,成都服務(wù)器托管,骨干網(wǎng)絡(luò)帶寬,享受低延遲,高速訪問。靈活、實(shí)現(xiàn)低成本的共享或公網(wǎng)數(shù)據(jù)中心高速帶寬的專屬高性能服務(wù)器。
2.隊(duì)列如果將儲存的數(shù)據(jù)都讀完就結(jié)束,列表可以反復(fù)讀取
例如:
二、具體介紹一下queue
在使用queue的時候要先引入queue模塊,創(chuàng)建對象~
其中queue可以創(chuàng)建出三種對象分別是
1.先進(jìn)先出行Queue(maxsize = ?)
通過上面的例子我們能發(fā)現(xiàn),put 方法是往隊(duì)列放數(shù)據(jù),但是隊(duì)列跟列表不同取完之后數(shù)據(jù)就沒有了,如果取的數(shù)據(jù)大于列表存放的數(shù)據(jù)就會卡住這時候有兩種解決辦法,第一種調(diào)用get_nowait()方法,這時候就會報異常queue.Empty,第二種就是從get自身解決,get(block = False),默認(rèn)的時候block是True。
2.后進(jìn)先出LifeQueue()是個縮寫是Last in first out
3.priorityQueue可以理解成vip,看你的心情讓那先出就先出
三、利用queue和多線程寫一個生產(chǎn)者消費(fèi)者
“?!?/p>
和
“隊(duì)列”
是數(shù)據(jù)結(jié)構(gòu),與具體的語言無關(guān)。
1.隊(duì)列先進(jìn)先出,棧先進(jìn)后出。
2.
對插入和刪除操作的"限定"。
棧是限定只能在表的一端進(jìn)行插入和刪除操作的線性表。
隊(duì)列是限定只能在表的一端進(jìn)行插入和在另一端進(jìn)行刪除操作的線性表。
從"數(shù)據(jù)結(jié)構(gòu)"的角度看,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同。但它們是完全不同的數(shù)據(jù)類型。除了它們各自的基本操作集不同外,主要區(qū)別是對插入和刪除操作的"限定"。
棧和隊(duì)列是在程序設(shè)計中被廣泛使用的兩種線性數(shù)據(jù)結(jié)構(gòu),它們的特點(diǎn)在于基本操作的特殊性,棧必須按"后進(jìn)先出"的規(guī)則進(jìn)行操作,而隊(duì)列必須按"先進(jìn)先出"
的規(guī)則進(jìn)行操作。和線性表相比,它們的插入和刪除操作受更多的約束和限定,故又稱為限定性的線性表結(jié)構(gòu)。
3.遍歷數(shù)據(jù)速度不同。棧只能從頭部取數(shù)據(jù)
也就最先放入的需要遍歷整個棧最后才能取出來,而且在遍歷數(shù)據(jù)的時候還得為數(shù)據(jù)開辟臨時空間,保持?jǐn)?shù)據(jù)在遍歷前的一致性隊(duì)列怎不同,他基于地址指針進(jìn)行遍歷,而且可以從頭或尾部開始遍歷,但不能同時遍歷,無需開辟臨時空間,因?yàn)樵诒闅v的過程中不影像數(shù)據(jù)結(jié)構(gòu),速度要快的多
棧(stack)是限定只能在表的一端進(jìn)行插入和刪除操作的線性表。
隊(duì)列(queue)是限定只能在表的一端進(jìn)行插入和在另一端進(jìn)行刪除操作的線性表。
從"數(shù)據(jù)結(jié)構(gòu)"的角度看,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同。但它們是完全不同的數(shù)據(jù)類型。除了它們各自的基本操作集不同外,主要區(qū)別是對插入和刪除操作的"限定"。
棧和隊(duì)列是在程序設(shè)計中被廣泛使用的兩種線性數(shù)據(jù)結(jié)構(gòu),它們的特點(diǎn)在于基本操作的特殊性,棧必須按"后進(jìn)先出"的規(guī)則進(jìn)行操作,而隊(duì)列必須按"先進(jìn)先出"的規(guī)則進(jìn)行操作。和線性表相比,它們的插入和刪除操作受更多的約束和限定,故又稱為限定性的線性表結(jié)構(gòu)。
在 Python 中定義 Celery 的時候,我們要引入 Broker,中文翻譯過來就是“中間人”的意思。在工頭(生產(chǎn)者)提出任務(wù)的時候,把所有的任務(wù)放到 Broker 里面,在 Broker 的另外一頭,一群碼農(nóng)(消費(fèi)者)等著取出一個個任務(wù)準(zhǔn)備著手做。這種模式注定了整個系統(tǒng)會是個開環(huán)系統(tǒng),工頭對于碼農(nóng)們把任務(wù)做的怎樣是不知情的。所以我們要引入 Backend 來保存每次任務(wù)的結(jié)果。這個 Backend 也是存儲任務(wù)的信息用的,只不過這里存的是那些任務(wù)的返回結(jié)果。我們可以選擇只讓錯誤執(zhí)行的任務(wù)返回結(jié)果到 Backend,這樣我們?nèi)』亟Y(jié)果,便可以知道有多少任務(wù)執(zhí)行失敗了。
其實(shí)現(xiàn)架構(gòu)如下圖所示:
可以看到,Celery 主要包含以下幾個模塊:
celery可以通過pip自動安裝。
broker 可選擇使用RabbitMQ/redis,backend可選擇使用RabbitMQ/redis/MongoDB。RabbitMQ/redis/mongoDB的安裝請參考對應(yīng)的官方文檔。
------------------------------rabbitmq相關(guān)----------------------------------------------------------
官網(wǎng)安裝方法:
啟動管理插件:sbin/rabbitmq-plugins enable rabbitmq_management 啟動rabbitmq:sbin/rabbitmq-server -detached
rabbitmq已經(jīng)啟動,可以打開頁面來看看 地址:
用戶名密碼都是guest 。進(jìn)入可以看到具體頁面。 關(guān)于rabbitmq的配置,網(wǎng)上很多 自己去搜以下就ok了。
------------------------------rabbitmq相關(guān)--------------------------------------------------------
項(xiàng)目結(jié)構(gòu)如下:
使用前,需要三個方面:celery配置,celery實(shí)例,需執(zhí)行的任務(wù)函數(shù),如下:
Celery 的配置比較多,可以在 官方配置文檔: 查詢每個配置項(xiàng)的含義。
當(dāng)然,要保證上述異步任務(wù)and下述定時任務(wù)都能正常執(zhí)行,就需要先啟動celery worker,啟動命令行如下:
需 啟動beat ,執(zhí)行定時任務(wù)時, Celery會通過celery beat進(jìn)程來完成。Celery beat會保持運(yùn)行, 一旦到了某一定時任務(wù)需要執(zhí)行時, Celery beat便將其加入到queue中. 不像worker進(jìn)程, Celery beat只需要一個即可。而且為了避免有重復(fù)的任務(wù)被發(fā)送出去,所以Celery beat僅能有一個。
命令行啟動:
如果你想將celery worker/beat要放到后臺運(yùn)行,推薦可以扔給supervisor。
supervisor.conf如下:
Python實(shí)現(xiàn)簡單多線程任務(wù)隊(duì)列
最近我在用梯度下降算法繪制神經(jīng)網(wǎng)絡(luò)的數(shù)據(jù)時,遇到了一些算法性能的問題。梯度下降算法的代碼如下(偽代碼):
defgradient_descent(): # the gradient descent code plotly.write(X, Y)
一般來說,當(dāng)網(wǎng)絡(luò)請求 plot.ly 繪圖時會阻塞等待返回,于是也會影響到其他的梯度下降函數(shù)的執(zhí)行速度。
一種解決辦法是每調(diào)用一次 plotly.write 函數(shù)就開啟一個新的線程,但是這種方法感覺不是很好。 我不想用一個像 cerely(一種分布式任務(wù)隊(duì)列)一樣大而全的任務(wù)隊(duì)列框架,因?yàn)榭蚣軐τ谖业倪@點(diǎn)需求來說太重了,并且我的繪圖也并不需要 redis 來持久化數(shù)據(jù)。
那用什么辦法解決呢?我在 python 中寫了一個很小的任務(wù)隊(duì)列,它可以在一個單獨(dú)的線程中調(diào)用 plotly.write函數(shù)。下面是程序代碼。
fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue):
首先我們繼承 Queue.Queue 類。從 Queue.Queue 類可以繼承 get 和 put 方法,以及隊(duì)列的行為。
def__init__(self, num_workers=1): Queue.Queue.__init__(self) self.num_workers=num_workers self.start_workers()
初始化的時候,我們可以不用考慮工作線程的數(shù)量。
defadd_task(self, task,*args,**kwargs): args=argsor() kwargs=kwargsor{} self.put((task, args, kwargs))
我們把 task, args, kwargs 以元組的形式存儲在隊(duì)列中。*args 可以傳遞數(shù)量不等的參數(shù),**kwargs 可以傳遞命名參數(shù)。
defstart_workers(self): foriinrange(self.num_workers): t=Thread(target=self.worker) t.daemon=True t.start()
我們?yōu)槊總€ worker 創(chuàng)建一個線程,然后在后臺刪除。
下面是 worker 函數(shù)的代碼:
defworker(self): whileTrue: tupl=self.get() item, args, kwargs=self.get() item(*args,**kwargs) self.task_done()
worker 函數(shù)獲取隊(duì)列頂端的任務(wù),并根據(jù)輸入?yún)?shù)運(yùn)行,除此之外,沒有其他的功能。下面是隊(duì)列的代碼:
我們可以通過下面的代碼測試:
defblokkah(*args,**kwargs): time.sleep(5) print“Blokkah mofo!” q=TaskQueue(num_workers=5) foriteminrange(1): q.add_task(blokkah) q.join()# wait for all the tasks to finish. print“Alldone!”
Blokkah 是我們要做的任務(wù)名稱。隊(duì)列已經(jīng)緩存在內(nèi)存中,并且沒有執(zhí)行很多任務(wù)。下面的步驟是把主隊(duì)列當(dāng)做單獨(dú)的進(jìn)程來運(yùn)行,這樣主程序退出以及執(zhí)行數(shù)據(jù)庫持久化時,隊(duì)列任務(wù)不會停止運(yùn)行。但是這個例子很好地展示了如何從一個很簡單的小任務(wù)寫成像工作隊(duì)列這樣復(fù)雜的程序。
defgradient_descent(): # the gradient descent code queue.add_task(plotly.write, x=X, y=Y)
修改之后,我的梯度下降算法工作效率似乎更高了。如果你很感興趣的話,可以參考下面的代碼。fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue): def__init__(self, num_workers=1):Queue.Queue.__init__(self)self.num_workers=num_workersself.start_workers() defadd_task(self, task,*args,**kwargs):args=argsor()kwargs=kwargsor{}self.put((task, args, kwargs)) defstart_workers(self):foriinrange(self.num_workers):t=Thread(target=self.worker)t.daemon=Truet.start() defworker(self):whileTrue:tupl=self.get()item, args, kwargs=self.get()item(*args,**kwargs)self.task_done() deftests():defblokkah(*args,**kwargs):time.sleep(5)print"Blokkah mofo!" q=TaskQueue(num_workers=5) foriteminrange(10):q.add_task(blokkah) q.join()# block until all tasks are doneprint"All done!" if__name__=="__main__":tests()
Queue 叫隊(duì)列,是數(shù)據(jù)結(jié)構(gòu)中的一種,基本上所有成熟的編程語言都內(nèi)置了對 Queue 的支持。
Python 中的 Queue 模塊實(shí)現(xiàn)了多生產(chǎn)者和多消費(fèi)者模型,當(dāng)需要在多線程編程中非常實(shí)用。而且該模塊中的 Queue 類實(shí)現(xiàn)了鎖原語,不需要再考慮多線程安全問題。
該模塊內(nèi)置了三種類型的 Queue,分別是 class queue.Queue(maxsize=0) , class queue.LifoQueue(maxsize=0) 和 class queue.PriorityQueue(maxsize=0) 。它們?nèi)齻€的區(qū)別僅僅是取出時的順序不一致而已。
Queue 是一個 FIFO 隊(duì)列,任務(wù)按照添加的順序被取出。
LifoQueue 是一個 LIFO 隊(duì)列,類似堆棧,后添加的任務(wù)先被取出。
PriorityQueue 是一個優(yōu)先級隊(duì)列,隊(duì)列里面的任務(wù)按照優(yōu)先級排序,優(yōu)先級高的先被取出。
如你所見,就是上面所說的三種不同類型的內(nèi)置隊(duì)列,其中 maxsize 是個整數(shù),用于設(shè)置可以放入隊(duì)列中的任務(wù)數(shù)的上限。當(dāng)達(dá)到這個大小的時候,插入操作將阻塞至隊(duì)列中的任務(wù)被消費(fèi)掉。如果 maxsize 小于等于零,則隊(duì)列尺寸為無限大。
向隊(duì)列中添加任務(wù),直接調(diào)用 put() 函數(shù)即可
put() 函數(shù)完整的函數(shù)簽名如下 Queue.put(item, block=True, timeout=None) ,如你所見,該函數(shù)有兩個可選參數(shù)。
默認(rèn)情況下,在隊(duì)列滿時,該函數(shù)會一直阻塞,直到隊(duì)列中有空余的位置可以添加任務(wù)為止。如果 timeout 是正數(shù),則最多阻塞 timeout 秒,如果這段時間內(nèi)還沒有空余的位置出來,則會引發(fā) Full 異常。
當(dāng) block 為 false 時,timeout 參數(shù)將失效。同時如果隊(duì)列中沒有空余的位置可添加任務(wù)則會引發(fā) Full 異常,否則會直接把任務(wù)放入隊(duì)列并返回,不會阻塞。
另外,還可以通過 Queue.put_nowait(item) 來添加任務(wù),相當(dāng)于 Queue.put(item, False) ,不再贅述。同樣,在隊(duì)列滿時,該操作會引發(fā) Full 異常。
從隊(duì)列中獲取任務(wù),直接調(diào)用 get() 函數(shù)即可。
與 put() 函數(shù)一樣, get() 函數(shù)也有兩個可選參數(shù),完整簽名如下 Queue.get(block=True, timeout=None) 。
默認(rèn)情況下,當(dāng)隊(duì)列空時調(diào)用該函數(shù)會一直阻塞,直到隊(duì)列中有任務(wù)可獲取為止。如果 timeout 是正數(shù),則最多阻塞 timeout 秒,如果這段時間內(nèi)還沒有任務(wù)可獲取,則會引發(fā) Empty 異常。
當(dāng) block 為 false 時,timeout 參數(shù)將失效。同時如果隊(duì)列中沒有任務(wù)可獲取則會立刻引發(fā) Empty 異常,否則會直接獲取一個任務(wù)并返回,不會阻塞。
另外,還可以通過 Queue.get_nowait() 來獲取任務(wù),相當(dāng)于 Queue.get(False) ,不再贅述。同樣,在隊(duì)列為空時,該操作會引發(fā) Empty 異常。
Queue.qsize() 函數(shù)返回隊(duì)列的大小。注意這個大小不是精確的,qsize() 0 不保證后續(xù)的 get() 不被阻塞,同樣 qsize() maxsize 也不保證 put() 不被阻塞。
如果隊(duì)列為空,返回 True ,否則返回 False 。如果 empty() 返回 True ,不保證后續(xù)調(diào)用的 put() 不被阻塞。類似的,如果 empty() 返回 False ,也不保證后續(xù)調(diào)用的 get() 不被阻塞。
如果隊(duì)列是滿的返回 True ,否則返回 False 。如果 full() 返回 True 不保證后續(xù)調(diào)用的 get() 不被阻塞。類似的,如果 full() 返回 False 也不保證后續(xù)調(diào)用的 put() 不被阻塞。
queue.Queue() 是 FIFO 隊(duì)列,出隊(duì)順序跟入隊(duì)順序是一致的。
queue.LifoQueue() 是 LIFO 隊(duì)列,出隊(duì)順序跟入隊(duì)順序是完全相反的,類似于棧。
優(yōu)先級隊(duì)列中的任務(wù)順序跟放入時的順序是無關(guān)的,而是按照任務(wù)的大小來排序,最小值先被取出。那任務(wù)比較大小的規(guī)則是怎么樣的呢。
注意,因?yàn)榱斜淼谋容^對規(guī)則是按照下標(biāo)順序來比較的,所以在沒有比較出大小之前 ,隊(duì)列中所有列表對應(yīng)下標(biāo)位置的元素類型要一致。
好比 [2,1] 和 ["1","b"] 因?yàn)榈谝粋€位置的元素類型不一樣,所以是沒有辦法比較大小的,所以也就放入不了優(yōu)先級隊(duì)列。
然而對于 [2,1] 和 [1,"b"] 來說即使第二個元素的類型不一致也是可以放入優(yōu)先級隊(duì)列的,因?yàn)橹恍枰容^第一個位置元素的大小就可以比較出結(jié)果了,就不需要比較第二個位置元素的大小了。
但是對于 [2,1] 和 1 [2,"b"] 來說,則同樣不可以放入優(yōu)先級隊(duì)列,因?yàn)樾枰容^第二個位置的元素才可以比較出結(jié)果,然而第二個位置的元素類型是不一致的,無法比較大小。
綜上,也就是說, 直到在比較出結(jié)果之前,對應(yīng)下標(biāo)位置的元素類型都是需要一致的 。
下面我們自定義一個動物類型,希望按照年齡大小來做優(yōu)先級排序。年齡越小優(yōu)先級越高。
本章節(jié)介紹了隊(duì)列以及其常用操作。因?yàn)殛?duì)列默認(rèn)實(shí)現(xiàn)了鎖原語,因此在多線程編程中就不需要再考慮多線程安全問題了,對于程序員來說相當(dāng)友好了。
當(dāng)前文章:python隊(duì)列的函數(shù) 隊(duì)列Python
分享鏈接:http://aaarwkj.com/article24/docpgce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、微信小程序、小程序開發(fā)、、網(wǎng)站設(shè)計公司、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)