An toàn chuỗi trong từ điển của Python


104

Tôi có một lớp học chứa từ điển

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

Và tôi đang chạy 4 luồng (một cho mỗi nhà hàng) gọi phương thức OrderBook.addOrder. Đây là chức năng được chạy bởi mỗi luồng:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

Điều này có an toàn không, hay tôi phải sử dụng khóa trước khi gọi addOrder?


2
Làm thế nào có thể có vấn đề khi mỗi chủ đề ghi vào một khóa khác nhau.
Jochen Ritzel

63
@Jochen: tùy thuộc vào cách thực hiện các phân đoạn, nhiều lỗi có thể xảy ra. Đây là một câu hỏi rất hợp lý.
Ned Batchelder

Câu trả lời:


94

Các cấu trúc tích hợp của Python an toàn theo luồng đối với các hoạt động đơn lẻ, nhưng đôi khi có thể khó nhận ra đâu là một câu lệnh thực sự trở thành nhiều phép toán.

Mã của bạn phải an toàn. Hãy ghi nhớ: một ổ khóa ở đây sẽ hầu như không thêm chi phí và sẽ giúp bạn yên tâm.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm có thêm chi tiết.


6
Đây là effbot.org lý do / cách thực hiện
hobs

1
Nên xem xét hoạt động đơn lẻ so với hoạt động tổng hợp, chẳng hạn như get-add-set .
andy

5
vấn đề là, khi tôi thường xuyên đọc / viết câu đọc đó, sự yên tâm đó sẽ khiến tôi phải trả giá rất nhiều.
Shihab Shahriar Khan

2
"một ổ khóa ở đây sẽ gần như không có chi phí": tại sao vậy?
tối đa

32

Có, các loại tích hợp vốn đã an toàn cho chuỗi: http://docs.python.org/glossary.html#term-global-interpreter-lock

Điều này đơn giản hóa việc triển khai CPython bằng cách làm cho mô hình đối tượng ( bao gồm các loại tích hợp quan trọng như dict ) an toàn một cách ngầm định trước truy cập đồng thời.


25
Đây không phải là một tính năng của Python, mà là của cpython .
phihag

8
Đúng, nhưng theo tôi hiểu, tích hợp sẵn trong Jython và IronPython cũng an toàn theo luồng ngay cả khi không sử dụng GIL (và nuốt không tải, nếu nó xuất hiện, cũng đề xuất loại bỏ GIL). Tôi cho rằng vì anh ấy không chỉ định trình thông dịch mà anh ấy đang sử dụng, nên ý anh ấy là trong CPython.

1
Đúng trong trường hợp của Jython: jython.org/jythonbook/en/1.0/…
Evgeni Sergeev

9

Hướng dẫn phong cách của Google khuyên bạn không nên dựa vào tính nguyên tử độc tài

Được giải thích chi tiết hơn tại: Phép gán biến Python có phải là nguyên tử không?

Không dựa vào tính nguyên tử của các loại cài sẵn.

Trong khi các kiểu dữ liệu tích hợp sẵn của Python như từ điển dường như có các phép toán nguyên tử, có những trường hợp góc mà chúng không phải là nguyên tử (ví dụ: nếu __hash__hoặc __eq__được triển khai dưới dạng các phương thức Python) và không nên dựa vào tính nguyên tử của chúng. Bạn cũng không nên dựa vào việc gán biến nguyên tử (vì điều này lại phụ thuộc vào từ điển).

Sử dụng Queuekiểu dữ liệu Hàng đợi của mô-đun làm cách ưu tiên để giao tiếp dữ liệu giữa các luồng. Nếu không, hãy sử dụng mô-đun luồng và các nguyên thủy khóa của nó. Tìm hiểu về cách sử dụng hợp lý các biến điều kiện để bạn có thể sử dụng threading.Conditionthay vì sử dụng các khóa cấp thấp hơn.

Và tôi đồng ý với điều này: đã có GIL trong CPython, vì vậy hiệu suất của việc sử dụng Khóa sẽ không đáng kể. Sẽ tốn kém hơn nhiều giờ để săn lỗi trong một cơ sở mã phức tạp khi các chi tiết triển khai CPython đó thay đổi vào một ngày nào đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.