Сиротные трассировки в sys._current_frames () - PullRequest
4 голосов
/ 11 апреля 2020

Вот эзотерический c pure- Python вопрос.

Я занимаюсь статистическим профилированием с использованием sys._current_frames(). то есть у меня есть фоновый поток, который запускается sys._current_frames() раз в секунду, выводит результаты в текстовый файл, а затем у меня есть некоторый код Python, который сортирует трассировки от наиболее распространенного к наименьшему.

Одно любопытное явление, которое я видел, - это следы, подобные этим:

  File "/opt/foo/bar.py", line 1437, in __iter__
    yield key

Этот yield - генератор, который я написал. Любопытно, что на этой трассировке есть только один кадр. Как это могло произойти? Другие трассировки имеют много кадров, либо с верхнего уровня процесса, либо с верхнего уровня кадра. Что означает эта однокадровая трассировка стека?

Одна теория, которая у меня была, заключается в том, что это замороженное состояние генератора, после того как он получил значение и ожидает, пока next снова будет вызван. Но я думаю, что я опроверг эту теорию с помощью отдельного эксперимента: я сделал генератор, гарантировал его приостановку, назвал sys._current_frames(), и я не видел такой трассировки стека.

1 Ответ

4 голосов
/ 17 апреля 2020

Как предупреждает документация sys._current_frames() ,

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

sys._current_frames() естественно склонен к условиям гонки в любой ситуации, когда вы не может гарантировать, что интересующие потоки приостановлены.


Как вы и подозревали, вы видите трассировку стека для приостановленного генератора. Когда генератор приостанавливается, его кадр стека не имеет родительских кадров. f_back имеет значение null.

sys._current_frames() извлекает кадры стека для текущих запущенных потоков, но к тому времени, когда вы посмотрите на эти кадры, они могут больше не работать. Если генератор приостанавливается между временем, когда вы звоните sys._current_frames(), и временем, когда вы проверяете кадр, это то, как он будет выглядеть. Вы также можете увидеть его поверх стека вызовов, который выглядит совершенно иначе, чем при фактическом вызове sys._current_frames(), если он возобновляется где-то еще.

Ваш тест не показал кадр генератора, потому что вы приостановили генератор до вызова sys._current_frames() вместо того, чтобы потом. Кадр стека генератора не был активным кадром какого-либо потока в этой точке.

...