Введение
Кажется, есть много предложений кресел и никаких рабочих примеров. Ни один из ответов, перечисленных здесь, даже не предлагает использовать многопроцессорность, и это немного разочаровывает и беспокоит. Как любители Python, мы должны поддерживать наши встроенные библиотеки, и хотя параллельная обработка и синхронизация никогда не бывает тривиальным вопросом, я считаю, что это можно сделать тривиальным при правильном проектировании. Это становится чрезвычайно важным в современных многоядерных архитектурах и не может быть подчеркнуто достаточно! Тем не менее, я далеко не удовлетворен многопроцессорной библиотекой, так как она все еще находится в зачаточном состоянии, с довольно большим количеством подводных камней, ошибок и направленностью на функциональное программирование (которое я ненавижу). В настоящее время я все еще предпочитаю модуль Pyro (который значительно опережает свое время) над многопроцессорным, поскольку многопроцессорное ограничение состоит в невозможности совместного использования вновь созданных объектов во время работы сервера. Метод класса «register» объектов менеджера будет фактически регистрировать объект только ДО запуска менеджера (или его сервера). Достаточно болтовни, больше кода:
Server.py
from multiprocessing.managers import SyncManager
class MyManager(SyncManager):
pass
syncdict = {}
def get_dict():
return syncdict
if __name__ == "__main__":
MyManager.register("syncdict", get_dict)
manager = MyManager(("127.0.0.1", 5000), authkey="password")
manager.start()
raw_input("Press any key to kill server".center(50, "-"))
manager.shutdown()
В приведенном выше примере кода Server.py использует многопроцессорный SyncManager, который может предоставлять синхронизированные общие объекты. Этот код не будет работать в интерпретаторе, потому что многопроцессорная библиотека довольно разборчива в том, как найти «вызываемый» для каждого зарегистрированного объекта. Запуск Server.py запустит настроенный SyncManager, который совместно использует словарь синдиката для использования несколькими процессами и может быть подключен к клиентам либо на одном компьютере, либо, если он запущен на IP-адресе, отличном от loopback, на других компьютерах. В этом случае сервер работает по шлейфу (127.0.0.1) на порту 5000. При использовании параметра authkey используются безопасные соединения при манипулировании синдикатом. При нажатии любой клавиши менеджер выключается.
Client.py
from multiprocessing.managers import SyncManager
import sys, time
class MyManager(SyncManager):
pass
MyManager.register("syncdict")
if __name__ == "__main__":
manager = MyManager(("127.0.0.1", 5000), authkey="password")
manager.connect()
syncdict = manager.syncdict()
print "dict = %s" % (dir(syncdict))
key = raw_input("Enter key to update: ")
inc = float(raw_input("Enter increment: "))
sleep = float(raw_input("Enter sleep time (sec): "))
try:
#if the key doesn't exist create it
if not syncdict.has_key(key):
syncdict.update([(key, 0)])
#increment key value every sleep seconds
#then print syncdict
while True:
syncdict.update([(key, syncdict.get(key) + inc)])
time.sleep(sleep)
print "%s" % (syncdict)
except KeyboardInterrupt:
print "Killed client"
Клиент также должен создать настроенный SyncManager, регистрирующий «syncdict», на этот раз без передачи вызываемого объекта для получения общего dict. Затем он использует настроенный SycnManager для подключения с использованием IP-адреса обратной связи (127.0.0.1) к порту 5000 и авторизации, устанавливающей безопасное соединение с менеджером, запущенным в Server.py. Он извлекает общий синтаксис dict, вызывая зарегистрированного вызываемого в диспетчере. Он запрашивает у пользователя следующее:
- Ключ синдиката для работы на
- Величина приращения значения, к которому обращается ключ каждый цикл
- Время сна за цикл в секундах
Затем клиент проверяет, существует ли ключ. Если этого не произойдет, это создает ключ на синдикате. Затем клиент входит в «бесконечный» цикл, в котором он обновляет значение ключа с шагом, спит указанное количество и печатает синдикт только для повторения этого процесса, пока не произойдет KeyboardInterrupt (Ctrl + C).
досадные проблемы
- Методы регистрации менеджера ДОЛЖНЫ вызываться до запуска менеджера, в противном случае вы получите исключения, даже если вызов dir для менеджера обнаружит, что у него действительно есть метод, который был зарегистрирован.
- Все манипуляции с dict должны выполняться с помощью методов, а не назначения dict (syncdict ["blast"] = 2 с треском провалится из-за того, что многопроцессорная обработка разделяет пользовательские объекты)
- Использование метода dict в SyncManager устранит досадную проблему № 2, за исключением того, что досадная проблема № 1 не позволяет регистрировать и распространять прокси, возвращенный SyncManager.dict (). (SyncManager.dict () может быть вызван только ПОСЛЕ запуска менеджера, а регистрация будет работать только ДО запуска менеджера, поэтому SyncManager.dict () полезен только при функциональном программировании и передаче прокси в Processes в качестве аргумента, подобного примеры документов делаю)
- Сервер И клиент должны зарегистрироваться, хотя интуитивно кажется, что клиент сможет выяснить это только после подключения к менеджеру (добавьте это в список разработчиков многопроцессорных систем пожеланий)
Закрытие
Надеюсь, вам понравился этот довольно подробный и немного трудоемкий ответ, как и мне. У меня были большие проблемы с пониманием того, почему я так много боролся с модулем многопроцессорной обработки, где Pyro делает его быстрым, и теперь, благодаря этому ответу, я ударил ногтем по голове. Я надеюсь, что это полезно для сообщества Python о том, как улучшить многопроцессорный модуль, так как я верю, что он имеет многообещающие возможности, но в зачаточном состоянии он не соответствует тому, что возможно. Несмотря на описанные досадные проблемы, я думаю, что это все еще вполне жизнеспособная альтернатива и довольно простая. Вы также можете использовать SyncManager.dict () и передать его процессам в качестве аргумента, как показано в документах, и, возможно, это будет еще более простое решение, в зависимости от ваших требований это просто неестественно для меня.