1. 程式人生 > >執行緒佇列排序(雙向佇列)

執行緒佇列排序(雙向佇列)

       利用 .append 和 .pop 方法,我們可以把列表當作棧或者佇列來用(比如,把 .append 和 .pop(0) 合起來用,就能模擬棧的“先進先出”的特點)。但是刪除列表的第一個元素(抑或是在第一個元素之前新增一個元素)之類的操作是很耗時的,因為這些操作會牽扯到移動列表裡的所有元素。        collections.deque 類(雙向佇列)是一個執行緒安全、可以快速從兩端新增或者刪除元素的資料型別。而且如果想要有一種資料型別來存放“最近用到的幾個元素”,deque 也是一個很好的選擇。這是因為在新建一個雙向佇列的時候,你可以指定這個佇列的大小,如果這個佇列滿員了,還可以從反向端刪除過期的元素,然後在尾端新增新的元素。示例 2-23 中有幾個雙向佇列的典型操作。

>>> from collections import deque
>>> dq = deque(range(10), maxlen=10) ➊
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3) ➋
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1) ➌
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11, 22, 33]) ➍
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10, 20, 30, 40]) ➎
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)

❶ maxlen 是一個可選引數,代表這個佇列可以容納的元素的數量,而且一旦設定,這個屬性就不能修改了。 ❷ 佇列的旋轉操作接受一個引數 n,當 n > 0 時,佇列的最右邊的 n個元素會被移動到佇列的左邊。當 n < 0 時,最左邊的 n 個元素會被移動到右邊。 ❸ 當試圖對一個已滿(len(d) == d.maxlen)的佇列做尾部新增操作的時候,它頭部的元素會被刪除掉。注意在下一行裡,元素 0 被刪除了。 ❹ 在尾部新增 3 個元素的操作會擠掉 -1、1 和 2。 ❺ extendleft(iter) 方法會把迭代器裡的元素逐個新增到雙向佇列的左邊,因此迭代器裡的元素會逆序出現在佇列裡。 表 2-3 總結了列表和雙向佇列這兩個型別的方法(object 類包含的方法除外)。        雙向佇列實現了大部分列表所擁有的方法,也有一些額外的符合自身設計的方法,比如說 popleft 和 rotate。但是為了實現這些方法,雙向佇列也付出了一些代價,從佇列中間刪除元素的操作會慢一些,因為它只對在頭尾的操作進行了優化。        append 和 popleft 都是原子操作,也就說是 deque 可以在多執行緒程式中安全地當作先進先出的棧使用,而使用者不需要擔心資源鎖的問題。

表2-3:列表和雙向佇列的方法(不包括由物件實現的方法)

# a_list.pop(p) 這個操作只能用於列表,雙向佇列的這個方法不接收引數。

     除了 deque 之外,還有些其他的 Python 標準庫也有對佇列的實現。queue提供了同步(執行緒安全)類 Queue、LifoQueue 和PriorityQueue,不同的執行緒可以利用這些資料型別來交換資訊。這三個類的構造方法都有一個可選引數 maxsize,它接收正整數作為輸入值,用來限定佇列的大小。但是在滿員的時候,這些類不會扔掉舊的元素來騰出位置。相反,如果佇列滿了,它就會被鎖住,直到另外的執行緒移除了某個元素而騰出了位置。這一特性讓這些類很適合用來控制活躍執行緒的數量。

multiprocessing   這個包實現了自己的 Queue,它跟 queue.Queue 類似,是設計給程序間通訊用的。同時還有一個專門的

multiprocessing.JoinableQueue 型別,可以讓任務管理變得更方便。

asyncio   Python 3.4 新提供的包,裡面有Queue、LifoQueue、PriorityQueue 和 JoinableQueue,這些類受

到 queue 和 multiprocessing 模組的影響,但是為非同步程式設計裡的任務管理提供了專門的便利。

heapq   跟上面三個模組不同的是,heapq 沒有佇列類,而是提供了heappush 和 heappop 方法,讓使用者可以把可變序列當作堆佇列或者優先佇列來使用。