Hướng dẫn python queue vs deque - hàng đợi python so với hàng đợi

Tôi cần một hàng đợi mà nhiều luồng có thể đặt nội dung vào và nhiều luồng có thể đọc từ đó.

Python có ít nhất hai lớp xếp hàng, Queue.Queuecollections.deque, với phần trước dường như sử dụng lớp sau. Cả hai đều tự nhiên là an toàn trong tài liệu.

Tuy nhiên, các tài liệu hàng đợi cũng nêu rõ:

Collections.Deque là một triển khai thay thế các hàng đợi không giới hạn với các hoạt động Ứng dụng nguyên tử nhanh () và popleft () không yêu cầu khóa.that do not require locking.

Mà tôi đoán tôi không hoàn toàn không cần thiết: điều này có nghĩa là deque không an toàn hoàn toàn?

Nếu có, tôi có thể không hiểu đầy đủ sự khác biệt giữa hai lớp. Tôi có thể thấy rằng hàng đợi thêm chức năng chặn. Mặt khác, nó mất một số tính năng deque như hỗ trợ cho người vận hành.

Truy cập trực tiếp vào đối tượng deque bên trong, là

x trong hàng đợi (). Deque

thread-safe?

Ngoài ra, tại sao hàng đợi sử dụng một mutex cho các hoạt động của nó khi deque an toàn đã an toàn?why does Queue employ a mutex for it's operations when deque is thread-safe already?

Hướng dẫn python queue vs deque - hàng đợi python so với hàng đợi

Federico Baù

4.5554 Huy hiệu vàng24 Huy hiệu bạc31 Huy hiệu đồng4 gold badges24 silver badges31 bronze badges

Hỏi ngày 4 tháng 4 năm 2009 lúc 14:03Apr 4, 2009 at 14:03

3

Queue.Queuecollections.deque phục vụ các mục đích khác nhau. Hàng đợi.queue nhằm mục đích cho phép các luồng khác nhau giao tiếp bằng cách sử dụng các tin nhắn/dữ liệu được xếp hàng, trong khi collections.deque chỉ đơn giản là được dự định là một cơ sở dữ liệu. Đó là lý do tại sao Queue.Queue có các phương pháp như

import time
import Queue
import collections

q = collections.deque()
t0 = time.clock()
for i in xrange(100000):
    q.append(1)
for i in xrange(100000):
    q.popleft()
print 'deque', time.clock() - t0

q = Queue.Queue(200000)
t0 = time.clock()
for i in xrange(100000):
    q.put(1)
for i in xrange(100000):
    q.get()
print 'Queue', time.clock() - t0
1,
import time
import Queue
import collections

q = collections.deque()
t0 = time.clock()
for i in xrange(100000):
    q.append(1)
for i in xrange(100000):
    q.popleft()
print 'deque', time.clock() - t0

q = Queue.Queue(200000)
t0 = time.clock()
for i in xrange(100000):
    q.put(1)
for i in xrange(100000):
    q.get()
print 'Queue', time.clock() - t0
2 và
import time
import Queue
import collections

q = collections.deque()
t0 = time.clock()
for i in xrange(100000):
    q.append(1)
for i in xrange(100000):
    q.popleft()
print 'deque', time.clock() - t0

q = Queue.Queue(200000)
t0 = time.clock()
for i in xrange(100000):
    q.put(1)
for i in xrange(100000):
    q.get()
print 'Queue', time.clock() - t0
3, trong khi collections.deque thì không. Queue.Queue không có ý định được sử dụng làm bộ sưu tập, đó là lý do tại sao nó thiếu các nhà điều hành
import time
import Queue
import collections

q = collections.deque()
t0 = time.clock()
for i in xrange(100000):
    q.append(1)
for i in xrange(100000):
    q.popleft()
print 'deque', time.clock() - t0

q = Queue.Queue(200000)
t0 = time.clock()
for i in xrange(100000):
    q.put(1)
for i in xrange(100000):
    q.get()
print 'Queue', time.clock() - t0
6.

Nó tập trung vào điều này: Nếu bạn có nhiều luồng và bạn muốn chúng có thể giao tiếp mà không cần khóa, bạn đang tìm kiếm Queue.Queue; Nếu bạn chỉ muốn một hàng đợi hoặc hàng đợi kết thúc kép làm cơ sở dữ liệu, hãy sử dụng collections.deque.

Cuối cùng, việc truy cập và thao túng các deque nội bộ của Queue.Queue đang chơi với lửa - bạn thực sự không muốn làm điều đó.

Đã trả lời ngày 4 tháng 4 năm 2009 lúc 15:26Apr 4, 2009 at 15:26

Keith Gaughankeith GaughanKeith Gaughan

Huy hiệu vàng 19.8K33 gold badges32 silver badges28 bronze badges

10

Nếu tất cả những gì bạn đang tìm kiếm là một cách an toàn cho chủ đề để chuyển các đối tượng giữa các luồng, thì cả hai sẽ hoạt động (cả cho FIFO và LIFO). Cho FIFO:a thread-safe way to transfer objects between threads, then both would work (both for FIFO and LIFO). For FIFO:

  • deque + notify_all: 0.469802
    Queue:              0.667279
    
    0 và
    deque + notify_all: 0.469802
    Queue:              0.667279
    
    1 là an toàn cho chủ đề
  • deque + notify_all: 0.469802
    Queue:              0.667279
    
    2 và
    deque + notify_all: 0.469802
    Queue:              0.667279
    
    3 là an toàn cho chủ đề

Note:

  • Các hoạt động khác trên
    deque + notify_all: 0.469802
    Queue:              0.667279
    
    4 có thể không an toàn, tôi không chắc chắn.
  • deque + notify_all: 0.469802
    Queue:              0.667279
    
    4 không chặn trên
    deque + notify_all: 0.469802
    Queue:              0.667279
    
    6 hoặc
    deque + notify_all: 0.469802
    Queue:              0.667279
    
    7 vì vậy bạn không thể dựa trên luồng luồng tiêu dùng của mình khi chặn cho đến khi một mặt hàng mới đến.

Tuy nhiên, có vẻ như Deque có lợi thế hiệu quả đáng kể. Dưới đây là một số kết quả điểm chuẩn tính bằng giâydeque has a significant efficiency advantage. Here are some benchmark results in seconds using CPython 2.7.3 for inserting and removing 100k items

deque 0.0747888759791
Queue 1.60079066852

Đây là mã điểm chuẩn:

import time
import Queue
import collections

q = collections.deque()
t0 = time.clock()
for i in xrange(100000):
    q.append(1)
for i in xrange(100000):
    q.popleft()
print 'deque', time.clock() - t0

q = Queue.Queue(200000)
t0 = time.clock()
for i in xrange(100000):
    q.put(1)
for i in xrange(100000):
    q.get()
print 'Queue', time.clock() - t0

Đã trả lời ngày 2 tháng 12 năm 2013 lúc 14:20Dec 2, 2013 at 14:20

Jonathan Livnijonathan LivniJonathan Livni

96.8K102 Huy hiệu vàng257 Huy hiệu bạc355 Huy hiệu Đồng102 gold badges257 silver badges355 bronze badges

6

Để biết thông tin, có một vé Python được tham chiếu cho Deque Thread-Safety (https://bugs.python.org/issue15329). Tiêu đề "Làm rõ phương pháp deque nào an toàn cho luồng"

Điểm mấu chốt ở đây: https://bugs.python.org/issue15329#msg199368

Deque's append (), appendleft (), pop (), popleft () và len (d) hoạt động an toàn cho chủ đề trong cpython. Các phương pháp phụ lục có một sắc lệnh ở cuối (đối với các trường hợp MaxLen đã được thiết lập), nhưng điều này xảy ra sau khi tất cả các bản cập nhật cấu trúc đã được thực hiện và các bất biến đã được khôi phục, vì vậy có thể coi các hoạt động này là nguyên tử.

Dù sao, nếu bạn không chắc chắn 100% và bạn thích độ tin cậy hơn hiệu suất, chỉ cần đặt một khóa tương tự;)

Đã trả lời ngày 12 tháng 12 năm 2015 lúc 11:41Dec 12, 2015 at 11:41

Hướng dẫn python queue vs deque - hàng đợi python so với hàng đợi

BadwolfbadwolfBadWolf

3453 Huy hiệu bạc4 Huy hiệu đồng3 silver badges4 bronze badges

Tất cả các phương pháp đơn tử trên

deque + notify_all: 0.469802
Queue:              0.667279
4 đều an toàn nguyên tử và an toàn. Tất cả các phương pháp khác cũng an toàn cho luồng. Những thứ như
deque + notify_all: 0.469802
Queue:              0.667279
9,
import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
0 mang lại các giá trị chính xác nhất thời. Nhưng hãy nghĩ rằng ví dụ: Khoảng
import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
1: Bạn không nhận được đảm bảo rằng tất cả các yếu tố trong
import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
2 được nộp liên tiếp khi các luồng khác cũng nối các phần tử ở cùng một phía - nhưng đó thường không phải là một yêu cầu trong giao tiếp giữa các luồng và cho nhiệm vụ được đặt câu hỏi.

Vì vậy,

deque + notify_all: 0.469802
Queue:              0.667279
4 nhanh hơn ~ 20 lần so với
import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
4 (sử dụng
deque + notify_all: 0.469802
Queue:              0.667279
4 dưới mui xe) và trừ khi bạn không cần API đồng bộ hóa "thoải mái" (chặn / hết thời gian _get, ..) Để thực hiện các tổ chức hàng đợi khác "hành vi lớp phụ, hoặc khi bạn tự mình chăm sóc những thứ như vậy, thì một
deque + notify_all: 0.469802
Queue:              0.667279
4 là một thỏa thuận tốt và hiệu quả cho giao tiếp giữa các luồng tốc độ cao.

Trong thực tế, việc sử dụng nặng của một c-mutex thêm và phương pháp bổ sung

import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
8, v.v. Các cuộc gọi phương pháp trong
import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
9 là do các ràng buộc tương thích ngược, quá khứ thiết kế và thiếu chăm sóc để cung cấp một giải pháp hiệu quả cho vấn đề tắc nghẽn tốc độ quan trọng này trong giao tiếp giữa các luồng . Một danh sách đã được sử dụng trong các phiên bản Python cũ hơn - nhưng thậm chí Danh sách.Append ()/. Pop (0) là & là nguyên tử và chủ đề ...

Đã trả lời ngày 19 tháng 4 năm 2017 lúc 16:08Apr 19, 2017 at 16:08

KXRKXRkxr

4.1911 Huy hiệu vàng44 Huy hiệu bạc28 Huy hiệu đồng1 gold badge44 silver badges28 bronze badges

1

Thêm

for item in a_deque:
   process(item)
0 vào mỗi
deque + notify_all: 0.469802
Queue:              0.667279
4
for item in a_deque:
   process(item)
2 và
for item in a_deque:
   process(item)
3 dẫn đến kết quả tồi tệ hơn nhiều đối với
deque + notify_all: 0.469802
Queue:              0.667279
4 so với cải tiến 20 lần đạt được theo mặc định
deque + notify_all: 0.469802
Queue:              0.667279
4 hành vi:

deque + notify_all: 0.469802
Queue:              0.667279

@Jonathan sửa đổi mã của anh ấy một chút và tôi nhận được điểm chuẩn bằng cách sử dụng CPython 3.6.2 và thêm điều kiện trong vòng lặp Deque để mô phỏng hàng đợi hành vi làm.

import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)

Và có vẻ như hiệu suất bị giới hạn bởi chức năng này

for item in a_deque:
   process(item)
6

Collections.Deque là một triển khai thay thế các hàng đợi không giới hạn với các hoạt động Ứng dụng nguyên tử nhanh () và popleft () không yêu cầu khóa. Hàng đợi tài liệu

Fantabolous

Huy hiệu vàng 20k652 Huy hiệu bạc48 Huy hiệu đồng6 gold badges52 silver badges48 bronze badges

Đã trả lời ngày 25 tháng 12 năm 2017 lúc 18:07Dec 25, 2017 at 18:07

Hướng dẫn python queue vs deque - hàng đợi python so với hàng đợi

nikan1996nikan1996nikan1996

611 Huy hiệu bạc2 Huy hiệu đồng1 silver badge2 bronze badges

deque + notify_all: 0.469802
Queue:              0.667279
4 là an toàn cho luồng. "Các hoạt động không yêu cầu khóa" có nghĩa là bạn không phải tự làm việc,
deque + notify_all: 0.469802
Queue:              0.667279
4 chăm sóc nó.

Nhìn vào nguồn

import time
from queue import Queue
import threading
import collections

mutex = threading.Lock()
condition = threading.Condition(mutex)
q = collections.deque()
t0 = time.clock()
for i in range(100000):
    with condition:
        q.append(1)
        condition.notify_all()
for _ in range(100000):
    with condition:
        q.popleft()
        condition.notify_all()
print('deque', time.clock() - t0)

q = Queue(200000)
t0 = time.clock()
for _ in range(100000):
    q.put(1)
for _ in range(100000):
    q.get()
print('Queue', time.clock() - t0)
4, deque bên trong được gọi là Queue.Queue0 và sử dụng mutex cho người truy cập và đột biến, do đó Queue.Queue1 không an toàn cho chủ đề để sử dụng.

Nếu bạn đang tìm kiếm một toán tử "trong", thì một deque hoặc hàng đợi có thể không phải là cấu trúc dữ liệu phù hợp nhất cho vấn đề của bạn.

n611x007

8.6907 Huy hiệu vàng58 Huy hiệu bạc97 Huy hiệu Đồng7 gold badges58 silver badges97 bronze badges

Đã trả lời ngày 4 tháng 4 năm 2009 lúc 14:42Apr 4, 2009 at 14:42

brian-brazilbrian-brazilbrian-brazil

29,8K5 Huy hiệu vàng85 Huy hiệu bạc81 Huy hiệu đồng5 gold badges85 silver badges81 bronze badges

4

.

deque.get () dường như là an toàn, nhưng tôi đã thấy rằng đang làm

for item in a_deque:
   process(item)

Có thể thất bại nếu một chủ đề khác là thêm các mục cùng một lúc. Tôi đã nhận được một RunTimEException đã phàn nàn "deque đột biến trong quá trình lặp lại".

Kiểm tra bộ sưu tập.c để xem hoạt động nào bị ảnh hưởng bởi điều này

Đã trả lời ngày 28 tháng 7 năm 2015 lúc 9:31Jul 28, 2015 at 9:31

2