Метод печати и GIL - PullRequest
       17

Метод печати и GIL

0 голосов
/ 14 сентября 2018

У меня есть многопоточная программа, и недавно я столкнулся с интересным явлением.

Если я вызову метод print в рабочем потоке, программа станет очень реактивной. Там нет большой хитрости, просто вызов метода print решает все.

Я недавно прочитал статью о глобальной блокировке интерпретатора Python, также известной как GIL, и в ней говорилось, что GIL выпускается после выполнения операций ввода-вывода. Как вы думаете, print вызов также связан с вводом / выводом?

Мне бы очень хотелось, чтобы моя программа реагировала, но, очевидно, неудобно выводить данные на стандартный вывод во время работы. Поэтому я попытался перенаправить вывод на /dev/null, но это не решило проблему:

with contextlib.redirect_stdout(None):
    print('')

Буду признателен, если у вас есть идея, чтобы я мог воспроизвести тот же эффект с помощью следующего вызова, но без вывода чего-либо:

print('')

Насколько я вижу, GIL высвобождается, пока переводчик работает для print(''). Может быть, мне нужен такой короткий перерыв, который освободит меня от GIL.

Это только для вашего сведения, но я попытался вызвать следующий метод:

print('', end='', flush=True)

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

Обновление

Если я позвоню usleep(1) из QThread, ожидая, что он будет спать 1 нас, тогда он ждет намного больше, чем я указал. Например. рабочий поток запускается каждые 1 мс, что очень медленно, потому что я ожидал запустить его в микросекундном порядке. Вызов print('') заставляет поток работать в порядке нескольких микросекунд. В этом смысле я называю это реактивным.

Обновление

Я чувствую, что что-то влияет на время выполнения потока, но это не usleep или time.sleep(). Тем не менее, я столкнулся с фактом, что print может отбросить блокиратор. Поэтому я хотел бы знать, что на самом деле выбивает блокиратор.

1 Ответ

0 голосов
/ 14 сентября 2018

Итак, здесь происходят две вещи.Во-первых, для самого GIL большинство функций ввода-вывода будет освобождать его непосредственно перед вызовом кода платформы, поэтому вызов print определенно освободит его.Это, естественно, позволит графику выполнения запустить другой поток.

Во-вторых, для usleep эта функция гарантированно спит не менее столько микросекунд, сколько вы просите, но в значительной степени это не так.спать меньше длительности такта планировщика ОС.В Linux это часто работает при 1000 Гц, 250 Гц или 100 Гц, но может немного отличаться.

Теперь, если вы хотите что-то более гранулярное, есть nanosleep вызов, который будет "занят-ждать" для задержек короче 2 мс вместо вызова в ядро.

...