Как скопировать функцию Python на удаленную машину и затем выполнить ее?
Я пытаюсь создать конструкцию в Python 3, которая позволит мне легко выполнить функцию на удаленной машине. Предполагая, что у меня уже есть tcp-сервер Python, который будет запускать функции, которые он получает, работая на удаленном сервере, я в настоящее время смотрю на использование декоратора, как
@execute_on(address, port)
Это создаст необходимый контекст, необходимый для выполнения функции, которую он украшает, а затем отправит функцию и контекст на tcp-сервер на удаленной машине, которая затем выполняет ее. Во-первых, это несколько вменяемое? А если нет, не могли бы вы порекомендовать лучший подход? Я немного погуглил, но не нашел ничего, что отвечало бы этим потребностям.
У меня есть быстрая и грязная реализация для tcp-сервера и клиента, так что я уверен, что это сработает. Я могу получить строковое представление функции (например, func), передаваемой декоратору
import inspect
string = inspect.getsource(func)
который затем может быть отправлен на сервер, где он может быть выполнен. Проблема в том, как получить всю контекстную информацию, необходимую для выполнения функции? Например, если func определяется следующим образом,
import MyModule
def func():
result = MyModule.my_func()
MyModule должен быть доступен для функции либо в глобальном контексте, либо в локальном контексте funcs на удаленном сервере. В этом случае это относительно тривиально, но это может быть намного сложнее в зависимости от того, когда и как используются операторы импорта. Есть ли простой и элегантный способ сделать это в Python? Лучшее, что я придумал на данный момент, - это использование библиотеки ast для извлечения всех операторов импорта, использование модуля inspect для получения строковых представлений этих модулей, а затем восстановление всего контекста на удаленном сервере. Не особенно элегантно, и я вижу много места для ошибок.
Спасибо за ваше время
5 ответов
Подход, который вы обрисовали в общих чертах, чрезвычайно рискован, если только удаленный сервер не будет как-то очень сильно защищен или "сильно изолирован" (например, "тюрьма" BSD) - любой, кто может отправлять ему функции, сможет запускать там произвольный код.
Предполагая, что у вас есть система аутентификации, которой вы полностью доверяете, возникает проблема "хрупкости", которую вы поняли - функция может зависеть от любых глобальных переменных, определенных в ее модуле в момент выполнения (которые могут отличаться от тех, которые вы можете обнаружить при проверке).: определение набора импортируемых модулей и, в более общем случае, глобальных переменных во время выполнения является проблемой полного по Тьюрингу).
Вы можете справиться с проблемой глобальных переменных, сериализовав глобальные переменные функции, а также саму функцию во время отправки ее для удаленного выполнения (независимо от того, сериализуете ли вы все эти вещи в читаемой строковой форме или нет, это небольшая проблема), Но это все еще оставляет вас с проблемой импорта, выполняемого внутри функции.
Если вы не хотите наложить некоторые ограничения на "удаленную" функцию, например "нет импорта внутри функции (и функций, вызываемых из нее)", я думаю, вы можете переопределить сервер __import__
(встроенная функция, которая используется всеми операторами импорта и предназначена для переопределения для особых нужд, таких как ваша;-), чтобы запросить дополнительный модуль у отправляющего клиента (конечно, для этого требуется, чтобы указанный клиент также имел "серверные" возможности, в том смысле, что он должен иметь возможность отвечать на такие "запросы модуля" от сервера).
Не можете ли вы наложить некоторые ограничения на функции, которые удалены, чтобы вернуть эту задачу обратно в область здравомыслия...?
Вы можете быть заинтересованы в проекте execnet.
execnet предоставляет тщательно протестированные средства для легкого взаимодействия с интерпретаторами Python через барьеры версий, платформ и сетей. Он имеет минимальный и быстрый API, предназначенный для следующих целей:
- распределять задачи по локальным или удаленным процессорам
- писать и развертывать гибридные многопроцессорные приложения
- написать сценарии для администрирования множества сред exec
http://codespeak.net/execnet/example/test_info.html
Я видел демонстрацию этого. Но никогда не использовал это сам.
Из вашего вопроса неясно, есть ли какие-то системные ограничения / требования для решения вашей проблемы таким способом. Если нет, то могут быть гораздо более простые и быстрые способы сделать это с помощью какой-либо инфраструктуры обмена сообщениями.
Например, вы можете рассмотреть вопрос о том, [сельдерей] [1]
[1]: http://ask.github.com/celery/getting-started/introduction.html удовлетворит ваши потребности.
Вероятно, это будет трудно сделать, и у вас возникнут проблемы с безопасностью, аргументами и т. Д. Возможно, вы можете просто запустить интерпретатор Python удаленно, которому может быть задан код с использованием сокета или службы HTTP, а не делать это для функции по функции уровень?
Какова ваша конечная цель с этим? Из вашего описания я не вижу причин, по которым вы не можете просто создать простой класс обмена сообщениями и отправить его экземпляры, чтобы дать команду удаленному компьютеру делать "вещи"..?
Что бы вы ни делали, вашей удаленной машине понадобится исходный код Python для выполнения, так почему бы не распространить там код и затем запустить его? Вы можете создать простой сервер, который будет принимать некоторые исходные файлы Python, извлекать их, импортировать соответствующие модули и затем запускать команду?