2013-04-27 30 views
8

Vì vậy, tôi thường có một sự hiểu biết khá tốt về cách Global Interpreter Lock (GIL) trong Python hoạt động. Về cơ bản, trong khi phiên dịch đang chạy, một luồng giữ GIL cho N ticks (trong đó N có thể được thiết lập bằng cách sử dụng sys.setcheckinterval), tại thời điểm đó GIL được giải phóng và một luồng khác có thể lấy GIL. Điều này cũng xảy ra nếu một luồng bắt đầu một hoạt động I/O.Python: GIL context - switching

Điều tôi hơi bối rối là cách tất cả điều này hoạt động với các mô-đun mở rộng C.

Nếu bạn có mô-đun mở rộng C mua lại GIL, và sau đó thực hiện một số mã python sử dụng PyEval_EvalCode, trình thông dịch có thể giải phóng GIL và đưa nó cho một số chủ đề khác không? Hay chuỗi C có được GIL giữ GIL vĩnh viễn cho đến khi PyEval_EvalCode trả về và GIL được phát hành rõ ràng trong C?

PyGILState gstate = PyGILState_Ensure(); 

.... 

/* Can calling PyEval_EvalCode release the GIL and let another thread acquire it?? */ 
PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict); 

PyGILState_Release(gstate); 

Trả lời

2

Có, thông dịch viên luôn có thể giải phóng GIL; nó sẽ đưa nó đến một số chủ đề khác sau khi nó đã giải thích đủ hướng dẫn, hoặc tự động nếu nó thực hiện một số I/O. Lưu ý rằng kể từ khi gần đây Python 3.x, tiêu chí không còn dựa trên số lượng các hướng dẫn thực hiện, nhưng vào thời gian đủ đã trôi qua.

Để có hiệu ứng khác, bạn cần có cách để lấy GIL ở chế độ "nguyên tử", bằng cách yêu cầu GIL không được phát hành cho đến khi bạn giải phóng nó một cách rõ ràng. Điều này là không thể cho đến nay (nhưng xem https://bitbucket.org/arigo/cpython-withatomic cho một phiên bản thử nghiệm).

+0

Xem [câu hỏi liên quan] của tôi (http://stackoverflow.com/questions/29317120/forcing-a-thread-to-block-all-other-threads-from-executing). Tôi không hiểu làm thế nào để giải quyết sự không thống nhất dường như giữa tuyên bố của bạn và tuyên bố trong Python Cookbook. – max

+0

Xem [Câu trả lời của Albert] (http://stackoverflow.com/a/29328066). –

1

Như Armin đã nói, GIL có thể được giải phóng bên trong PyEval_EvalCode. Khi nó quay trở lại, tất nhiên nó lại được mua lại.

Cách tốt nhất là đảm bảo rằng mã của bạn có thể xử lý điều đó. Ví dụ, incref bất kỳ đối tượng mà bạn có con trỏ C trước khi GIL có thể được phát hành. Ngoài ra, hãy cẩn thận nếu có thể có trường hợp mã Python lại gọi hàm rất giống nhau. Nếu bạn có một mutex khác ở đó, bạn có thể dễ dàng kết thúc trong một khóa chết. Sử dụng mutexes đệ quy an toàn và trong khi chờ đợi chúng, bạn nên giải phóng GIL sao cho chuỗi ban đầu có thể giải phóng các mutex đó.

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