2013-07-16 37 views
7

Tôi đã không làm việc với luồng trong Python ở tất cả và hỏi câu hỏi này như một người lạ hoàn toàn.Is collections.defaultdict thread-safe?

Tôi tự hỏi nếu defaultdict là an toàn chỉ. Hãy để tôi giải thích nó:

Tôi có

d = defaultdict(list) 

mà tạo ra một danh sách cho thiếu phím theo mặc định. Giả sử tôi có nhiều chủ đề bắt đầu thực hiện việc này cùng một lúc:

d['key'].append('value') 

Cuối cùng, tôi phải kết thúc bằng ['value', 'value']. Tuy nhiên, nếu defaultdict không phải là thread-safe, nếu thread 1 sản lượng để chủ đề 2 sau khi kiểm tra if 'key' in dict và trước d['key'] = default_factory(), nó sẽ gây ra đan xen, và các chủ đề khác sẽ tạo danh sách trong d['key'] và thêm 'value' lẽ.

Sau đó, khi chuỗi 1 đang thực thi lại, nó sẽ tiếp tục từ d['key'] = default_factory() sẽ hủy danh sách và giá trị hiện tại và chúng tôi sẽ kết thúc bằng ['key'].

Tôi đã xem CPython source code for defaultdict. Tuy nhiên, tôi không thể tìm thấy bất kỳ ổ khóa hoặc mutexes. Tôi đoán nó không phải là thread-an toàn miễn là nó được ghi lại như vậy.

Một số người tối qua trên IRC cho biết rằng có GIL trên Python, vì vậy khái niệm chỉ an toàn về chủ đề. Một số nói luồng không nên được thực hiện bằng Python. Tôi khá bối rối. Ý tưởng?

+0

https://groups.google.com/forum/#!topic/comp.lang.python/9ZnBQrYun1w có thể giúp –

Trả lời

12

Đây là chủ đề an toàn, trong trường hợp cụ thể này.

Để biết lý do tại sao điều quan trọng là phải hiểu khi Python chuyển chủ đề. CPython chỉ cho phép chuyển đổi giữa các luồng giữa các bước bytecode của Python. Đây là nơi GIL đến; mỗi mã N byte hướng dẫn khóa được phát hành và một chuyển đổi chủ đề có thể diễn ra.

d['key'] được xử lý bởi một bytecode (BINARY_SUBSCR) kích hoạt phương thức .__getitem__() được gọi trên từ điển.

Một defaultdict, cấu hình với list như nhà máy giá trị mặc định, xử lý các phương pháp dict.__getitem__()hoàn toàn trong C, các GIL là không bao giờ được mở khóa, làm dict[key] tra cứu chủ đề an toàn.

Lưu ý chứng chỉ đó; nếu bạn tạo một cá thể defaultdict với một nhà máy giá trị mặc định khác nhau, một mã sử dụng mã Python (ví dụ: lambda: [1, 2, 3]), tất cả các cược sẽ bị tắt vì điều đó có nghĩa là mã C gọi lại vào mã Python và GIL có thể được phát hành lại trong khi thực hiện bytecode cho hàm lambda. Tương tự, nếu nhà máy được viết bằng mã C giải phóng GIL một cách rõ ràng, thì công tắc chủ đề có thể diễn ra và an toàn luồng là ngoài cửa sổ.

+0

Vì nó [dường như] không có trong tài liệu, điều này nghe có vẻ giống như một chi tiết thực hiện CPython - vẫn còn hữu ích để biết, mặc dù. – martineau

+2

+1 để đề cập rằng các nhà máy được viết bằng Python có thể kích hoạt phát hành GIL. Thật không may, nó thậm chí còn nhiều hơn nữa: GIL có thể kích hoạt bất kỳ 'Py_DECREF' nếu đối tượng được giải phóng và có' __del__'. Bằng cách này, ngay cả mã C thuần túy cũng có thể vô tình gây ra sự giải phóng bệnh lý GIL - thừa nhận, nhưng nó có thể xảy ra. – user4815162342

+2

Khá thú vị khi nhà phát triển nên biết về các bản phát hành GIL giữa việc thực thi mã C/Python qua lại. Cảm ơn. –