Приложение WSGI работает в своем собственном потоке (или процессе). При работе в контейнере WSGI Twisted это поток, отличный от потока, в котором работает реактор. Большинство API Twisted не являются поточно-ориентированными: их можно вызывать только в потоке реактора.
Итак, основной способ вызова Twisted API из приложения WSGI - это использование reactor.callFromThread
, которое является поточно-ориентированным и вызывает функцию, вызываемую в потоке реактора:
...
reactor.callFromThread(pbRemote.callRemote, "someMethod", some, args)
Однако, это отбрасывает результат, который вы, вероятно, хотите. Однако просто построить API поверх reactor.callFromThread
, который сохраняет результат, и есть реализация этого и в Twisted:
from twisted.internet.threads import blockingCallFromThread
...
result = blockingCallFromThread(reactor, pbRemote.callRemote, "someMethod", some, args)
Этот вызов будет блокироваться до тех пор, пока не сработает Отложенный, возвращенный callRemote
, а затем вернет результат этого Отложенного.
Если вы хотите позвонить, сделать какую-то другую работу, а затем дождаться окончания разговора, вам нужно проявить немного творчества. Вам нужно сделать вызов и получить фактический Deferred
, который он возвращает, но не блокировать его:
resultHolder = blockingCallFromThread(
reactor, lambda: [pbRemote.callRemote("someMethod", some, args)])
И тогда вы можете делать то, что вам нужно. И когда вы будете готовы дождаться результата вызова PB:
result = blockingCallFromThread(reactor, lambda: resultHolder[0])
Это все гораздо более неловко, чем использование Twisted в однопоточном сценарии, поэтому действительно может быть проще использовать собственные API-интерфейсы Twisted Web, а не создавать приложение WSGI. Помните, что одна из основных целей WSGI - разрешить разработку приложений, переносимых на разные серверы - Twisted, Apache и т. Д. Если вы действительно используете Twisted API в своем приложении WSGI, то он вообще не переносим.