Возможно ли программно построить стек (один или несколько фреймов стека) в CPython и начать выполнение с произвольной кодовой точки? Представьте себе следующий сценарий:Можно ли программно построить кадр стека Python и начать выполнение в произвольной точке кода?
У вас есть рабочий процесс двигателя, где рабочие процессы могут быть скриптового в Python с некоторыми конструкциями (например, ветвление, ожидание/присоединения), что призывы к двигателю документооборота.
Блокирующий вызов, такой как ожидание или объединение, устанавливает условие слушателя в механизме диспетчеризации событий с хранилищем постоянной памяти.
У вас есть сценарий рабочего процесса, который вызывает условие ожидания в движке, ожидая некоторого состояния, которое будет передано позже. Это устанавливает слушателя в механизме диспетчеризации событий.
Состояние сценария рабочего процесса, соответствующие стеки кадров, включая счетчик программ (или эквивалентное состояние), сохраняются - поскольку условие ожидания может происходить через несколько дней или месяцев.
В то же время механизм рабочего процесса может быть остановлен и перезапущен, что означает, что он должен иметь возможность программно хранить и восстанавливать контекст сценария рабочего процесса.
Событие диспетчерского двигателя запускает событие, которое ожидает условие ожидания.
Механизм рабочего процесса считывает сериализованное состояние и стек и восстанавливает поток со стеком. Затем он продолжает выполнение в точке, где была вызвана услуга ожидания.
Вопрос
Может ли это быть сделано с помощью переводчика неизмененным Python? Еще лучше, может ли кто-нибудь указать мне на какую-то документацию, которая может охватывать такие вещи или пример кода, который программно создает фрейм стека и запускает выполнение где-то посередине блока кода?
Edit: Для уточнения «неизмененного интерпретатора», я не возражаю, используя C API (есть достаточно информации в PyThreadState, чтобы сделать это?), Но я не хочу ковыряться внутренностями интерпретатора Python и необходимо создать модифицированный.
Обновление: Из некоторых начальных расследований можно получить контекст выполнения с PyThreadState_Get()
. Это возвращает состояние потока в PyThreadState
(определенный в pystate.h
), который имеет ссылку на стек стека в frame
. Кадр стека сохраняется в struct typedef'd до PyFrameObject
, который определен в frameobject.h
. PyFrameObject
имеет поле f_lasti
(реквизит до bobince), у которого есть программный счетчик, выраженный как смещение от начала кодового блока.
Это последнее из хороших новостей, потому что это означает, что до тех пор, пока вы сохраняете фактический скомпилированный блок кода, вы должны иметь возможность реконструировать локали для как можно большего количества кадров стека и повторно запустить код.Я бы сказал, это означает, что это теоретически возможно без необходимости создания модифицированного интерпонента python, хотя это означает, что код, вероятно, будет неудобно и тесно связан с конкретными версиями интерпретатора.
Три оставшиеся проблемы:
состояние транзакции и «сага» откат, который, вероятно, может быть достигнуто с помощью своего рода метакласса взлома можно было бы использовать, чтобы построить O/R Mapper. Однажды я создал прототип, поэтому у меня есть справедливое представление о том, как это можно сделать.
Прочное сериализованное состояние транзакции и произвольные местные жители. Это может быть достигнуто путем чтения
__locals__
(который доступен из фрейма стека) и программного построения вызова для рассола. Однако я не знаю, что, если таковые имеются, может быть здесь.Управление версиями и обновление рабочих процессов. Это несколько сложнее, поскольку система не предоставляет никаких символических привязок для узлов рабочего процесса. Все, что у нас есть, это привязка Чтобы сделать это, нужно было бы определить смещения всех точек входа и сопоставить их с новой версией. Возможно, это возможно сделать вручную, но я подозреваю, что было бы сложно автоматизировать. Это, пожалуй, самое большое препятствие, если вы хотите поддержать эту возможность.
Update 2:PyCodeObject
(code.h
) имеет список адр (f_lasti
) -> номер строки отображения в PyCodeObject.co_lnotab
(поправьте меня, если неправильно здесь). Это может быть использовано для облегчения процесса миграции для обновления рабочих процессов до новой версии, поскольку замороженные указатели инструкций могут быть сопоставлены с соответствующим местом в новом скрипте, выполняемом с точки зрения номеров строк. Все еще довольно грязный, но немного более перспективный.
Обновление 3: Я думаю, что ответ на этот вопрос может быть Stackless Python. Вы можете приостановить выполнение задач и сериализовать их. Я не разработал, будет ли это также работать со стеклом.
Отличный вопрос - я бы не стал ненавидеть того, кто должен отлаживать этот проект! –