Возникла необходимость в решении такой задачи: как обмениваться данными между разными интерпретаторами Python?! Отыскал несколько решений, но хочу рассказать об одном, на мой взгляд, самом удобном.
Выбор подхода
Для начала я пытался выбрать наиболее удобное решение из множества. Может не корректно сравнивать message queue, сокеты и RPC, но я исходил от задачи. Вот что доступно:
Сокеты TCP
Использование сокетов, наиболее простой способ взаимодействия, можно передавать любые данные, но код придётся насыщать реализацией собственного протокола. Этот путь тернист, и ошибки неизбежны. Вывод: подходит, но сложно.
Библиотека ZeroMQ
Очень перспективная разработка brokerless очередь сообщений. Реализована как библиотека pyzmq и pyzmq-static. Для первого случая нужно установить саму ZeroMQ — написанная на C разделяемая библиотека. Вторая уже содержит бинарник. Начиналось всё весьма забавно, код работал отлично, пока я не перешёл к IronPython…
Для IronPython pyzmq не реализована, но не проблема, есть же .NET Integration, что позволяет использовать clrzmq — биндинг для .NET; и вот здесь начались проблемы. Бинарник доступен через плагин для VisualStudio — nuget, поэтому пришлось бибилотеку компилировать.Скачал исходник, там всё удобно, скрипт собирается командой build, но не всё так просто. Версия 2 не собралась вообще, хотя зависимости разрешила через nuget корректно (может взял битый commit?), 3 бета собралась, но падала даже на примере из tutorial )
В итоге и сети отыскал бинарник 2-ки, но это меня совсем не порадовало. Всё заработало, но API в 3-ке так сильно изменился, что не хотелось потом переписывать код по сто раз. Вывод: хорошо, но сыро вне чистого Python.
Pyro, поджигай!
Поначалу решил добивать 0mq, но вспомнил о сущеcтвовании такой библиотеки как Pyro: библиотеки из кризисных 90-х, которая прекрасно поживает и развивается. Не буду перечислять все её плюсы, сейчас интересует только один — взаимодействие интерпретаторов. Сразу к делу, пробуем пример из tutorial, но с той разницей, что запускаем всё под разными интерпретаторами (код не менял, только вписал свой ник).
Запускаем сервер имён под Jython, кстати, вот и первый огромный плюс, у 0mq сервер имён ещё не доделан:
Ого! Завелось...
Теперь регистрируем сервер, который будет работать под IronPython:
Регистрация прошла успешно.
Следующий шаг, запуск клиента. Делаем под классическим питоном (у меня их сразу много стоит, но запускал EPD):
Прекрасно! Всё сработало.
Версия pickle
Как вариант, попробовал ещё запускать одну из частей под Python 3. Без хака не сработало :( Последний использует pickle третьей версии + нет некоторых стандартных модулей (удалены, перенесены), хотя это поведение можно обойти. Но главная причина, Pyro4 иcпользует pickle для сериализации, при этом самую последнюю версию. Вот как удалось обойти этот недостаток и подключиться Python 3 к IronPython 2 и Jython 2:
import pickle
pickle.HIGHEST_PROTOCOL = 2
Это нужно добавить в код клиента перед импортом Pyro. Всё сработало:
Обратите внимание на использование 64-битного Python.
Кстати, как вариант, можно использовать библиотеку pyrolite для прямого подключения из .NET или Java без Python интерпретатора. Это фактически мини pickle.
В целом решение с Pyro пока понравилось больше других, если же система содержит очень много компонент разных версий, то, наверное, выгоднее будет использовать 0mq. Хотя я пока остановлюсь всё же на Pyro4.
Автор: deko