Найти - Пользователи
Полная версия: почему возникают задержки на пустом месте???
Начало » Python для экспертов » почему возникают задержки на пустом месте???
1 2 3 4
Андрей Светлов
Это как раз и называется GIL (Global Interpreter Lock).
Смотрим sys.getcheckinterval(). По умолчанию - 100.
Это значит вот что:
* Питон захватывает lock
* исполняет 100 инструкций байткода
* отпускает lock
* здесь может произойти переключение потока для многопоточной программы. А может и не произойти.
* захватывает опять - и пошли сначала.

Однопоточная программа тоже постоянно захватывает/отпускает lock - это не отключается.

Такое - для каждого потока. Т.е. если один работает - второй ждет. Т.к. одномоментно поток выполняется только на одном проце - то на четырехядерной машине увидим примерно по 25% на ядро.

Я достаточно полно объяснил?
o7412369815963
Андрей Светлов
Это как раз и называется GIL (Global Interpreter Lock).
* здесь может произойти переключение потока для многопоточной программы. А может и не произойти.
(в нашем случае тест однопоточный, а переключения есть, и не на 100 инструкций, а на милион (целых 16 мс). )

а где можно скачать python-safe-theard? я где-то вычитал что он без GIL
Андрей Светлов
Эээ.
Повторяю. Специально для танкистов.
Каждые 100 инструкций байткода (внимание, не ассемблера, питон исполняет свой байткод интерпретатором!) происходит следующее:
- отпустили GIL
- захватили GIL
и это делается даже в однопоточном приложении.
#ifdef WITH_THREAD
if (interpreter_lock) {
/* Give another thread a chance */

if (PyThreadState_Swap(NULL) != tstate)
Py_FatalError("ceval: tstate mix-up");
PyThread_release_lock(interpreter_lock);

/* Other threads may run now */

PyThread_acquire_lock(interpreter_lock, 1);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");

/* Check for thread interrupts */

if (tstate->async_exc != NULL) {
x = tstate->async_exc;
tstate->async_exc = NULL;
PyErr_SetNone(x);
Py_DECREF(x);
why = WHY_EXCEPTION;
goto on_error;
}
}
#endif
PyThreadState_Swap - простая запись в глобальную переменную, а PyThread_release_lock/PyThread_acquire_lock - хуже.
Реализация зависит от платформы.
На Windows это interlocked variable+Event (“тяжелый” объект ядра).
Для Posix - все еще хитрее. Это либо семафор - либо pthread_mutex_t + pthread_cond_t (все они - тоже “ядерные” объекты).
В любом случае получается, что PyThread_release_lock/PyThread_acquire_lock - довольно затратные операции.

И тут можно влететь на затык.
Antoine Pitrou сейчас крутит вариант с более легковесным GIL для py3k. В какой релиз это попадет - непонятно. Скорее всего, только в 3.2 (2.7, вероятно, пролетает).
Из переписки видно, что со старой (она же текущая) реализацией все более или менее нормально на linux, несколько хуже на windows и, как я понял, совсем плохо на mac - там иногда можно попасть на довольно большие задержки.

P.S.
- Питон без GIL - это компиляция без флага WITH_THREAD, который ставится по умолчанию.
- время выполнения одного байткода сильно от этого самого байткода зависит. Диапазон от долей микросекунды до секунд в наиболее злых случаях. Но в любом разе это много-много ассемблерных команд.
o7412369815963
Андрей Светлов
- Питон без GIL - это компиляция без флага WITH_THREAD, который ставится по умолчанию.
потоки в нем будут работать? хочу сам разруливать проблему общих ресурсов
Андрей Светлов
Нет, не будут. Тут уж что-то одно.

Мы говорим о программировании на “чистом” питоне - без всяких C embedded?
Тогда как вы будете разруливать из Питона его же интерпретатор? Ведь общие ресурсы как раз в нем, в самых что ни на есть недрах.
o7412369815963
Андрей Светлов
Нет, не будут. Тут уж что-то одно.

Мы говорим о программировании на “чистом” питоне - без всяких C embedded?
Тогда как вы будете разруливать из Питона его же интерпретатор? Ведь общие ресурсы как раз в нем, в самых что ни на есть недрах.
есть же мютексы, семафоры или что-то типа того…
Андрей Светлов
Есть. Но GIL нужен для того, чтобы работал сам Python.
Объекты синхронизации из threading помогут вам в организации мультипоточной работы вашего кода.
И бессильны, если интерпретатор сам по себе не поддерживает многопоточнось.

Так вот, GIL - существенная часть этой поддержки. Выкидываете его - получаете простой однопоточный Питон.
o7412369815963
а можно сделать так что-б в определенном куске кода GIL переключения не было, типа: gil-off blabla() gil-on ?
Андрей Светлов
:)

Знаете, это примерно как, гммм, гадить против ветра.
Теоретически, если аккуратно исполнять - возможно.
На практике же прийдется виртуозить и при этом - никакого преимущества по сравнению с классическим способом.

Создавайте C Extension, в котором внутри BEGIN_THREADS/END_THREADS делайте все, что нужно. Даже это будет проще, чем возиться с GIL напрямую. И гораздо безопасней.
pioner
Андрей Светлов
Такое - для каждого потока. Т.е. если один работает - второй ждет.
Второй ждет освобождения ресурсов, а не завершения потока, ведь в этом смысл многопоточности. И если есть свободные ядра у проца, то почему на них не запускается новый поток?

Андрей Светлов
Т.к. одномоментно поток выполняется только на одном проце - то на четырехядерной машине увидим примерно по 25% на ядро.
Т.е. поток на 100% одно ядро не может загрузить?
Андрей Светлов
Я достаточно полно объяснил?
Получается, что сам интерпретатор однопоточен? если прерывается для проверки потоков на исполнение?
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB