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