Сериализация несериализуемых объектов Python с использованием указателей Cython - PullRequest
0 голосов
/ 17 июня 2019

Я разрабатывал отладчик Python в течение последних 4 лет (время от времени), который был чрезвычайно полезен для отладки сложного кода Python. Отладчик действует как трассировка программы, позволяя мне видеть все, что делает моя программа. Это достигается за счет использования того, что составляет набор операторов печати. ​​

Например, следующий код Python:

if(x == True):
    Trace.If("User has enabled 'x'")

    n = Trace.Variable(n + x + y)

else:
    Trace.Else("User has not enabled anything")

    pass

Выводит следующее в файл журнала или базу данных (при условии, что условие «if» выполнено):

Counter - Timestamp - Filename - Function - Line of Code - If - User has enabled 'x'
Counter - Timestamp - Filename - Function - Line of Code - Variable - n = 13

Старая версия моего отладчика выполняла каждую операцию трассировки в основном процессе / потоке (связанном с программой, которую отслеживал мой отладчик). Хотя это не было проблемой для приложений, которые не были критичны по времени, программы, которые не могли быть правильно отслежены Из-за этого я начал работу над многопоточной версией моего отладчика Python (около 1 года). Хотя повышение скорости от перехода к однопоточной версии моей библиотеки отладки до многопоточной версии моей библиотеки отладки очень помогло (так как большая часть моей библиотеки была тяжелой для операций ввода-вывода), этого было недостаточно критичные ко времени приложения Python.

Затем я начал работать над версией моей библиотеки отладки с несколькими процессорами (около 0,5 года) и получил все для работы, за исключением операторов отладки, связанных с анализом объектов Python. Например, следующее:

n = Trace.Variable(...some Python object...)

... попытается проанализировать объект Python, возвращая то, что составляет сериализованную версию рассматриваемого объекта Python. Например, следующий код:

testABC = Trace.Variable([1, 2, [3, 4, {'Bacon': 0, 'Ham': 1, 'Cheese': 2, 'Eggs': 3456}]])

... выведет следующие данные трассировки / отладки:

Counter - Timestamp - Filename - Function - Line of Code - Variable - testABC : (list) - [0] : (integer) - 1, [1] : (integer) - 2, [2] : (list) - [2][0] : (integer) - 3, [2][1] : (integer) - 4, [2][2] : (dictionary) - [2][2]{Bacon} : (integer) - 0, [2][2]{Ham} : (integer) - 1, [2][2]{Cheese} : (integer) - 2 and [2][2]{Eggs} : (integer) - 3456

К сожалению, часть библиотеки, которая обрабатывает анализ объектов Python, может быть медленной (в зависимости от анализируемого объекта Python). Чтобы предотвратить замедления в основном процессе выполнения / потоке, я пытаюсь проанализировать объекты Python в отдельном процессе Python. Проблема в том, что некоторые объекты Python не могут быть сериализованы (например, кадр или проверка).

Я пробовал все типы библиотек сериализации (например, Pickle, Dill и т. Д.), А также распределенную вычислительную библиотеку (например, ExecNet, RPyC и т. Д.), Но не могу передать несериализуемые объекты Python в отдельный процесс. Причина, по которой это является проблемой, заключается в том, что моя библиотека отладки Python предназначена для отладки / отслеживания любых сценариев Python. Если случается, что скрипт анализирует несериализуемый объект Python, мне нужно выполнить анализ этого объекта Python в основном процессе / потоке выполнения (который, как упоминалось ранее, может быть очень медленным).

Я рассмотрел использование интерпретаторов Python, которые позволяют отключить GIL (глобальную блокировку интерпретатора) в надежде выполнить этот дорогостоящий анализ в отдельном / параллельном потоке. Такие интерпретаторы, как Jython или IronPython, в настоящее время поддерживают только Python 2.7 (что является проблемой, поскольку моя библиотека отлаживает скрипты Python 3.0+). Я также рассмотрел интерпретаторы, которые могут ускорить выполнение Python (в надежде снизить затраты на выполнение дорогостоящего анализа в основном процессе / потоке), например PyPy, но главная проблема, которую я имею с PyPy, заключается в том, что он поддерживает Windows (и Python 3 в некоторой степени), кажется незначительным. К тому же, требование переустановки всех библиотек для PyPy также является проблемой (особенно если учесть, что не все библиотеки Python полностью поддерживаются - хотя я уверен, что они над этим работают).

С учетом всего сказанного у меня было последнее решение, которое я надеялся опробовать. Прежде чем сделать это, я надеялся обсудить решение с кем-то на форуме Stack Overflow, прежде чем его кодировать (поскольку я не уверен, что оно будет работать). Псевдокод для решения следующий:

1. Process 1 - Passes Python object (to be analyzed) to a Cython function.

2. Process 1 - Cython function stores Python object in memory and returns the memory address of the Python object.

3. Process 1 - Passes memory address of Python object (stored by Cython function) to a separate Python process (Process 2).

4. Process 2 - Receives memory address of Python object (stored by Cython function from Process 1) and passes the address to a Cython function.

5. Process 2 - Cython function pulls the Cython object pointing to the memory address, and returns a proxy of the original object.

6. Process 2 - Analyzes the Python object (returned by Cython function).

Вопрос 1. Возможно ли это (учитывая, что Python сам по себе не поддерживает передачу объектов по ссылке на другой процесс)?

Вопрос 2 - Если это так, будет ли сборщик мусора в Python освобождать объект, как только я выйду из функции Cython (из шага 2), или он останется в памяти (при условии, что Cython полагается на программиста для освобождения памяти - точно так же, как в с)?

Вопрос 3 - Будет ли шаг 5 возвращать объект Python или мне придется преобразовать объект C в объект Python (если так, как бы я это сделал)?

Извиняюсь за длинный вопрос. Любая помощь будет принята с благодарностью.

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...