2012-09-12 29 views
12

Tôi có một số chức năng mà tương tác nạp module python sử dụng __import__nhập khẩu bên trong của một sợi Python

thời gian gần đây tôi stumbled khi một số bài viết về một "khóa nhập khẩu" bằng Python, có nghĩa là, một khóa đặc biệt cho hàng nhập khẩu (không chỉ GIL). Nhưng bài viết đã cũ nên có lẽ điều đó không còn đúng nữa.

Điều này khiến tôi băn khoăn về việc thực hành nhập trong chuỗi.

  1. Are import/__import__ có an toàn không?
  2. Họ có thể tạo khóa chết không?
  3. Chúng có thể gây ra các vấn đề về hiệu suất trong ứng dụng luồng không?

EDIT 12 tháng 9 năm 2012

Cảm ơn bạn đã trả lời lớn Soravux. Vì vậy, nhập khẩu là chủ đề an toàn, và tôi không lo lắng về deadlocks, kể từ khi các chức năng sử dụng __import__ trong mã của tôi không gọi cho nhau.

Bạn có biết khóa có được mua ngay cả khi mô-đun đã được nhập không? Nếu đúng như vậy, có lẽ tôi nên tìm trong sys.modules để kiểm tra xem mô-đun đã được nhập chưa trước khi thực hiện cuộc gọi đến __import__.

Chắc chắn điều này sẽ không tạo ra nhiều khác biệt trong CPython vì có GIL. Tuy nhiên, nó có thể tạo ra rất nhiều sự khác biệt về các triển khai khác như Jython hoặc python stackless.

EDIT 19 tháng chín năm 2012

Về Jython, đây là những gì họ nói trong doc:

http://www.jython.org/jythonbook/en/1.0/Concurrency.html#module-import-lock

Python hiện, tuy nhiên, xác định một khóa mô-đun nhập khẩu, đó là thực hiện bởi Jython. Khóa này được mua bất cứ khi nào nhập bất kỳ tên nào. Điều này đúng cho dù việc nhập có đi qua câu lệnh nhập , nội dung tương đương __import__ hoặc mã có liên quan hay không. Đó là điều quan trọng cần lưu ý là ngay cả khi mô-đun tương ứng đã nhập , khóa nhập mô-đun sẽ vẫn được mua lại nếu chỉ một thời gian ngắn.

Vì vậy, có vẻ như bạn nên kiểm tra sys.modules trước khi nhập, để tránh bị khóa. Bạn nghĩ sao?

+1

Tôi tưởng tượng chúng là chủ đề an toàn, vì như bạn nói, trình thông dịch sẽ chặn các lần nhập. Tôi muốn được quan tâm để tìm hiểu xem họ có thể gây ra deadlocks trong bất kỳ cách nào khác hơn so với điển hình không luồng thông tư nhập khẩu. –

Trả lời

8

Nhập bình thường là chuỗi an toàn vì chúng có khóa nhập trước khi thực thi và nhả nó sau khi quá trình nhập hoàn tất. Nếu bạn thêm nhập khẩu tùy chỉnh của riêng bạn bằng cách sử dụng các móc có sẵn, hãy chắc chắn thêm lược đồ khóa này vào nó. Các thiết bị khóa trong Python có thể được truy cập bởi mô-đun imp (imp.lock_held()/acquire_lock()/release_lock()).

Sử dụng khóa nhập này sẽ không tạo bất kỳ lỗi khóa hoặc lỗi phụ thuộc nào ngoài các phụ thuộc vòng tròn là already known.

Cuộc gọi cấp thấp để tạo chuỗi là clone trên Linux, luồng trong Python sau đó là hoạt động giống như ngã ba. Việc phân nhánh và nhân bản áp dụng các hành vi khác nhau trên các phân đoạn bộ nhớ khác nhau. Ví dụ, chỉ có ngăn xếp không được chia sẻ bởi các chủ đề, so với các nhánh nhân bản nhiều phân đoạn hơn (Dữ liệu (thường là COW), Ngăn xếp, Mã, Heap), có hiệu quả không chia sẻ nội dung của nó. Cơ chế nhập trong Python sử dụng không gian tên chung là không phải được đặt trên ngăn xếp, do đó sử dụng phân đoạn được chia sẻ với chủ đề của nó. Vì các tác dụng phụ (ví dụ: những thay đổi trong bộ nhớ) của các công việc nhập khẩu trong cùng một phân đoạn, nó hoạt động như một chương trình đơn luồng. Tuy nhiên, hãy cẩn thận khi sử dụng các thư viện an toàn của luồng trong các mục nhập của bạn trên các chương trình đa luồng. Nó sẽ gây ra tình trạng lộn xộn để sử dụng các cuộc gọi đến các chức năng không phải là chủ đề an toàn trong môi trường như vậy.

Bằng cách này, các chương trình luồng trong Python bị GIL sẽ không cho phép tăng hiệu suất trừ khi chương trình của bạn bị ràng buộc hoặc dựa vào thư viện C hoặc thư viện an toàn bên ngoài (vì chúng phát hành GIL trước khi thực thi) . Chạy trong hai luồng cùng hàm được nhập sẽ không thực thi đồng thời vì GIL này. Lưu ý rằng đây chỉ là một hạn chế của CPython và các triển khai khác của Python sẽ có một hành vi khác.

Để trả lời chỉnh sửa của bạn: các mô-đun được nhập đều được lưu trữ bởi Python. Nếu mô-đun đã được tải trong bộ nhớ cache, nó sẽ không được chạy lại và câu lệnh nhập (hoặc hàm) sẽ trả về ngay lập tức. Bạn không phải tự mình thực hiện tra cứu bộ nhớ cache trong sys.modules, Python thực hiện điều đó cho bạn và sẽ không khóa bất cứ thứ gì, ngoài GIL để tìm kiếm sys.modules.

Để trả lời chỉnh sửa thứ hai: Tôi muốn duy trì mã đơn giản hơn là cố gắng tối ưu hóa cuộc gọi đến thư viện tôi sử dụng (trong trường hợp này là thư viện chuẩn). Lý do là thời gian cần thiết để thực hiện một cái gì đó thường là cách quan trọng hơn thời gian cần thiết để nhập khẩu các mô-đun thực hiện nó. Hơn nữa, thời gian cần thiết để duy trì loại mã này trong suốt dự án là cao hơn so với thời gian thực hiện. Tất cả đều tóm tắt: "thời gian lập trình có giá trị hơn thời gian của CPU".

+0

Cảm ơn bạn đã trả lời tuyệt vời. Tôi bây giờ tự hỏi nếu khóa nhập khẩu được mua ngay cả khi một mô-đun đã được nhập trước đó (xem chỉnh sửa trong câu hỏi ban đầu của tôi). –

+0

Câu trả lời đã chỉnh sửa để phản ánh câu hỏi đã chỉnh sửa của bạn. Điểm tốt về các hương vị khác của Python. – Soravux

+1

Tôi tình cờ gặp phần này của tài liệu: http://docs.python.org/library/threading.html#importing-in-threaded-code, tên này có thêm một số khía cạnh khác. – Alfe

Các vấn đề liên quan