У меня есть многопоточная программа, и недавно я столкнулся с интересным явлением.
Если я вызову метод 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
может выкинуть блокировщик. Поэтому я хотел бы знать, что на самом деле отбрасывает блокировщик.
print
— относительно медленная функция, поэтому потенциально она может изменить время работы функций, которые ее используют. Будьте осторожны, так как вы можете просто удачно скрыть состояние гонки из-за добавления функцииprint
. - person all or None   schedule 14.09.2018uleep(1)
класса PyQt QThread, но, похоже, он спал намного дольше, чем я указал. Поэтому я удалилusleep
и понял, что поток становится очень реактивным, просто вызываяprint('')
. - person Doofah   schedule 14.09.2018usleep(1)
из QThread, ожидая, что он заснет на 1 мкс, то он будет ждать намного дольше, чем я указал. Например. рабочий поток запускается каждую 1 мс, что очень медленно, потому что я ожидал запускать его в микросекундном порядке. Вызовprint('')
запускает поток через несколько микросекунд. В этом смысле я называю его реактивным. - person Doofah   schedule 14.09.2018usleep
илиtime.sleep()
. Однако я столкнулся с тем, чтоprint
может выкинуть блокировщик. Поэтому я хотел бы знать, что на самом деле отбрасывает блокировщик. - person Doofah   schedule 14.09.2018time.sleep(0)
; это должно просто дать GIL, а затем немедленно встать в очередь, чтобы получить его снова. Тем не менее, если вы работаете в Windows, функции WinAPI для блокировки ожиданий (на основе которых построены GIL и все другие блокирующие ожидания по времени) не имеют очень хорошей детализации; если он вообще спит, а другой поток не выпускает GIL самостоятельно, скорее всего, для возврата потребуется несколько миллисекунд. - person ShadowRanger   schedule 14.09.2018