2013-04-27 2 views
8

Итак, у меня есть довольно хорошее представление о том, как работает Global Interpreter Lock (GIL) в Python. По сути, в то время как интерпретатор работает, один поток содержит GIL для N тиков (где N можно установить с помощью sys.setcheckinterval), после чего GIL освобождается, а другой поток может получить GIL. Это также происходит, если один поток начинает операцию ввода-вывода.Python: контекст GIL - переключение

Я немного смущен, так как все это работает с модулями расширения C.

Если у вас есть модуль расширения C, который приобретает GIL, а затем выполняет некоторый код python с использованием PyEval_EvalCode, может ли интерпретатор освободить GIL и передать его в другой поток? Или поток C, который приобрел GIL, постоянно удерживает GIL до тех пор, пока не вернется PyEval_EvalCode, и GIL будет явно выпущен в 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); 

ответ

2

Да, переводчик может всегда выпускать GIL; он передаст его в другой поток после того, как он интерпретирует достаточно инструкций или автоматически, если он выполняет некоторые операции ввода-вывода. Обратите внимание, что с недавнего Python 3.x критерии больше не зависят от количества выполненных команд, а от того, прошло ли достаточно времени.

Чтобы получить другой эффект, вам понадобится способ получить GIL в «атомном» режиме, попросив GIL не выпускаться, пока вы не освободите его явно. Это невозможно до сих пор (но см. https://bitbucket.org/arigo/cpython-withatomic для экспериментальной версии).

+0

См. Мой [родственный вопрос] (http://stackoverflow.com/questions/29317120/forcing-a-thread-to-block-all-other-threads-from-executing). Я не понимаю, как разрешить кажущуюся несогласованность между вашим заявлением и заявлением в Cookbook Python. – max

+0

См. [Ответ Альберта] (http://stackoverflow.com/a/29328066). –

1

Как сказал Армин, GIL может быть выпущен внутри PyEval_EvalCode. Когда он возвращается, он, конечно, снова приобретается.

Лучший способ - просто убедиться, что ваш код может справиться с этим. Например, увеличивайте любые объекты, где у вас есть указатели C до того, как GIL может быть освобожден. Кроме того, будьте осторожны, если могут быть случаи, когда код Python снова вызывает ту же самую функцию. Если у вас есть еще один мьютекс, вы можете легко оказаться в режиме блокировки. Используйте рекурсивно-безопасные мьютексы и, ожидая их, вы должны освободить GIL, чтобы исходный поток мог выпускать такие мьютексы.

Смежные вопросы