Ааа. Когда я спрашивал - имел в виду
>>> def f():
... if -1 in xrange(10**12): pass
>>> import dis
>>> dis.dis(f)
3 0 LOAD_CONST 1 (-1)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_CONST 4 (1000000000000)
9 CALL_FUNCTION 1
12 COMPARE_OP 6 (in)
15 JUMP_IF_FALSE 4 (to 22)
18 POP_TOP
19 JUMP_FORWARD 1 (to 23)
>> 22 POP_TOP
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Проверка на ‘in’ делается в COMPARE_OP. GIL не освобождается, что очень неприятно.
В реальном коде таких ситуаций практически не бывает.
“70% тратиться на запрос к БД, 30% генерация страницы из них 10% ушло на gil” - неправильно так считать.
Если шаблонизатор написан на питоне, то блокируются все 30%. Т.е. в процессе следует запускать три потока (может - четыре).
С третьей стороны, заводить процессов больше, чем имеется ядер - бессмысленно. Да и БД тоже нужно работать, если она заведена на той же машине.
На самом деле, конечно, картина гораздо сложнее. Кажется, правильные цифры подбираются только эмпирически, глядя на графики загрузки.
К тому же GIL - не единственная блокировка в программе. Как минимум в DBAPI их еще пачка (а есть еще и фреймворк, который тоже может быть под вопросом). Раскидывание на процессы хорошо помогает еще и в таких вещах.