Как скопировать функцию python на удаленную машину и затем выполнить ее? - PullRequest
7 голосов
/ 03 июня 2010

Я пытаюсь создать конструкцию в 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 должен быть доступен для функции либо в глобальном контексте, либо в локальном контексте функции на удаленном сервере. В этом случае это относительно тривиально, но это может быть намного сложнее в зависимости от того, когда и как используются операторы импорта. Есть ли простой и элегантный способ сделать это в Python? Лучшее, что я придумал на данный момент, - это использование библиотеки ast для извлечения всех операторов импорта, использование модуля inspect для получения строковых представлений этих модулей, а затем восстановление всего контекста на удаленном сервере. Не особенно элегантно, и я вижу много места для ошибок.

Спасибо за ваше время

Ответы [ 5 ]

2 голосов
/ 03 июня 2010

Подход, который вы обрисовали в общих чертах, крайне рискован, если только удаленный сервер не очень сильно защищен или не «сильно изолирован» (например, «тюрьма» BSD) - любой, кто может отправлять ему функции, сможет запускать произвольный код там.

Предполагая, что у вас есть система аутентификации, которой вы полностью доверяете, возникает проблема «хрупкости», которую вы осознали - функция может зависеть от любых глобальных переменных, определенных в ее модуле в момент выполнения (которые могут отличаться от глобальных). обнаружение путем проверки: определение набора импортируемых модулей и, в более общем случае, глобальных переменных во время выполнения является проблемой, полной по Тьюрингу).

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

Если вы не хотите наложить некоторые ограничения на "удаленную" функцию, такие как "нет импорта внутри функции (и функций, вызываемых из нее)", я думаю, вы могли бы иметь переопределение сервера __import__ (встроенная функция, которая используется всеми операторами импорта и предназначена для переопределения для особых нужд, таких как ваша ;-), чтобы запросить дополнительный модуль у отправляющего клиента (конечно, для этого требуется указанный клиент также имеет «серверные» возможности, поскольку он должен иметь возможность отвечать на такие «запросы модуля» от сервера).

Разве вы не можете наложить некоторые ограничения на удаленные функции, чтобы вернуть эту задачу обратно в область здравомыслия ...?

2 голосов
/ 03 июня 2010

Вас может заинтересовать проект execnet .

execnet предоставляет тщательно протестированные средства для легкого взаимодействия с интерпретаторами Python через барьеры версий, платформ и сетей. Он имеет минимальный и быстрый API, предназначенный для следующих целей:

  • распределять задачи по локальным или удаленным процессорам
  • написание и развертывание гибридных многопроцессорных приложений
  • написать сценарии для администрирования множества сред exec

http://codespeak.net/execnet/example/test_info.html#get-information-from-remote-ssh-account

Я видел демонстрацию этого. Но никогда не использовал это сам.

1 голос
/ 03 июня 2010

Из вашего вопроса непонятно, есть ли какие-то системные ограничения / требования для решения вашей проблемы таким способом. Если нет, то могут быть гораздо более простые и быстрые способы сделать это с помощью какой-либо инфраструктуры обмена сообщениями.

Например, вы можете подумать, [Сельдерей] [1]

[1]: http://ask.github.com/celery/getting-started/introduction.html удовлетворит ваши потребности.

0 голосов
/ 03 июня 2010

Это, вероятно, будет трудно сделать, и у вас возникнут проблемы с безопасностью, аргументами и т. Д. Может быть, вы можете просто запустить интерпретатор Python удаленно, которому может быть передан код с использованием сокета или службы HTTP, вместо того, чтобы делать это для функции по уровню функции?

0 голосов
/ 03 июня 2010

Какова ваша конечная цель с этим? Из вашего описания я не вижу причин, по которым вы не можете просто создать простой класс обмена сообщениями и отправить его экземпляры, чтобы дать команду удаленному компьютеру делать «вещи» ..?

Что бы вы ни делали, вашей удаленной машине понадобится исходный код Python для выполнения, так почему бы не распространить там код и затем запустить его? Вы можете создать простой сервер, который будет принимать некоторые исходные файлы Python, извлекать их, импортировать соответствующие модули и затем запускать команду?

...