Запустите pika ioloop в фоновом режиме или используйте пользовательский ioloop - PullRequest
4 голосов
/ 11 марта 2011

У меня такое ощущение, что на самом деле это не должно быть таким уж сложным, но пока у меня небольшой успех.

Скажем, у меня есть класс под названием PikaClass, который упаковывает pika и предоставляетнекоторые бизнес-методы.

def PikaClass(object):
  def __init__(self):
     # connect to the broker
     self.connection = pika.SelectConnection(<connection parameters>, self.on_connect)
     # ..other init stuff..

  def on_connect(self, connection):
     # called when the connection has been established 
     # ..open a channel, declare some queues, etc.

  def start(self):
     # start the polling loop 
     self.connection.ioloop.start()

  def foo(self, **kwargs):
     # do some business logic, e.g., send messages to particular queues

Интуитивно понятно, чего я хотел бы достичь: пользователь создает экземпляр PikaClass, устанавливает цикл в фоновом режиме, а затем взаимодействует с объектом, вызываянекоторые бизнес-методы

p = PikaClass()
p.start()
bar = p.foo(..)

Проблема в том, что p.start () блокирует и предотвращает взаимодействие основного кода с объектом после вызова start ().Моей первой мыслью было заключить вызов в поток:

Thread(target=p.start()).start()
bar = p.foo(..)

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

Я также пытался использовать AsyncoreConnection вместо SelectConnection и вызывать _connect () напрямую (вместо использования ioloop)но это не имеет никакого эффекта (ничего не происходит).

Так как я могу запустить ioloop в фоновом режиме или, по крайней мере, запустить свой собственный ioloop?

Примечание: это Python 2.6 onwin64 (xp) с последней пикой 0.9.4

Ответы [ 3 ]

8 голосов
/ 27 июля 2012

Вы вызываете 'p.start' вместо передачи его в качестве параметра.Код должен быть:

Thread(target=p.start).start()

Thread будет вызывать p.start при выполнении Thread.start.

Я не уверен, что это решит вашу проблему, но это может помочь вамдостичь решения.

6 голосов
/ 03 мая 2011

GIL здесь не проблема, потому что ioloop тратит почти все свое время на системный вызов select (2) , в течение которого GIL освобождается и другие потоки Python могут работать выключи и выполняй другие задания.

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

Другой подход заключается в том, чтобы только start() ioloop после того, как вы получили сообщение для отправки, и метод, получающий ответ, останавливает ioloop, чтобы ваша программа снова получила контроль. Вы можете сделать ioloop возврат рано с:

    connection.ioloop.poller.open = False

и затем не забудьте установить его обратно на True перед повторным вызовом start(), чтобы дождаться другого ответа.

0 голосов
/ 11 марта 2011

Вам может понадобиться второй процесс, я не очень разбираюсь в pika, но если это чистый python, тогда он захочет сохранить GIL - помните, что вы можете выполнять только один поток за один процесс, независимо от того, как у вас много ядер из-за ограничений в счетчике ссылок, используемых для замечательной сборки мусора в Python.

Если вы запускаете новый процесс до того, как вы делаете / что-нибудь / еще в своем блоке if __name__ == "__main__":, и отключаете его в ожидании событий в цикле, вы можете отправить второму процессу инструкцию выполнить часть работы, а затем ждать чтобы отправить результат обратно к вам. Возможно, вы захотите внедрить какую-то систему индексации, чтобы вы могли перевести свою работу в другой процесс и забыть об этом, пока вам не понадобится ответ.

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

Это один из тех немногих случаев, когда Python вручает вам пистолет только с вежливой запиской, в которой говорится, что не следует направлять его на вашу ногу.

...