烧瓶应用程序中的zerorpc在apache服务器中启动时无效,但在pycharm启动时工作正常

时间:2014-05-27 13:22:18

标签: python apache python-2.7 flask zeromq

我正在使用flask应用程序来显示使用零rpc订阅者读取的数据。 虽然我在使用Pycharm启动应用程序时开发工作正常但是一旦部署在Apache服务器中,订阅者就无法获取任何数据。基本上,即使发布者正在发布数据,也不会调用订阅者中的方法。

由于

编辑:(添加更多信息):

在app_start.py

from gevent import monkey
monkey.patch_all()
from flask import Flask
app = Flask(__name__)

import stratgy_subscriber
startegy_state_info_provider = stratgy_subscriber.StartegyStateInfoProvider()
@app.route('/')
def strategy_info():
    return startegy_state_info_provider.ip_port_to_subscriber_map[('0.0.0.0', '4249')]

if __name__ == '__main__':
    startegy_state_info_provider.start_subscriber('0.0.0.0', '4249')
    app.run()

我使用以下代码连接到订阅者。 在stratgy_subscriber.py

from gevent import monkey
monkey.patch_all()

class StartegyStateInfoProvider(object):

  def __init__(self):  
      self.ip_port_to_subscriber_map = {}

  def start_subscriber(machine_ip, port):
      strategy_state_subscriber = StrategyStateSubscriber()
      ip_port_to_subscriber_map[(machine_ip, port)] = strategy_state_subscriber
      end_point = 'tcp://' + machine_ip + ':' + port
      strategy_state_subscriber = zerorpc.Subscriber(strategy_state_subscriber)
      strategy_state_subscriber.connect(end_point)
      gevent.spawn(strategy_state_subscriber.run)

class StrategyStateSubscriber():
  def __init__(self):
    self.strategy_id_to_info_map = {}
  def update_strategy_state(self, strategy_id, updated_strategy_state): 
    from datetime import datetime
    current_time = datetime.strftime(datetime.now(), '%H:%M:%S')
    updated_strategy_state.append(current_time)
    print updated_strategy_state
    strategy_id_to_info_map[strategy_id] = updated_strategy_state

这是发布者`

endpoint = "tcp://0.0.0.0:4249"
publisher = zerorpc.Publisher()
publisher.bind(endpoint)

for a in xrange(0, 1000):
    info = [False, a * a, 3 * a, a % 20, a % 50]
    publisher.update_strategy_state(a, info)
    if a < 50:
        gevent.sleep(1)
    elif a >= 50:
        gevent.sleep(2)

订阅后,即gevent.spawn(strategy_state_subscriber.run),每次发布者发布未发生的数据时,都应调用update_strategy_state。

我遇到以下异常:

[Wed May 28 11:24:03 2014] [error] Traceback (most recent call last):
[Wed May 28 11:24:03 2014] [error]   File "/home/sricharan/git_ceres_viewer/src/strategy_state_subscription.py", line 68, in subscribe
[Wed May 28 11:24:03 2014] [error]     subscriber = zerorpc.Subscriber(service)
[Wed May 28 11:24:03 2014] [error]   File "/usr/local/lib/python2.7/dist-packages/zerorpc/core.py", line 371, in __init__
[Wed May 28 11:24:03 2014] [error]     zmq_socket=zmq.SUB)
[Wed May 28 11:24:03 2014] [error]   File "/usr/local/lib/python2.7/dist-packages/zerorpc/core.py", line 312, in __init__
[Wed May 28 11:24:03 2014] [error]     super(Puller, self).__init__(zmq_socket, context=context)
[Wed May 28 11:24:03 2014] [error]   File "/usr/local/lib/python2.7/dist-packages/zerorpc/socket.py", line 34, in __init__
[Wed May 28 11:24:03 2014] [error]     self._events = Events(zmq_socket_type, context)
[Wed May 28 11:24:03 2014] [error]   File "/usr/local/lib/python2.7/dist-packages/zerorpc/events.py", line 177, in __init__
[Wed May 28 11:24:03 2014] [error]     self._socket = zmq.Socket(self._context, zmq_socket_type)
[Wed May 28 11:24:03 2014] [error]   File "/usr/local/lib/python2.7/dist-packages/zerorpc/gevent_zmq.py", line 61, in __init__
[Wed May 28 11:24:03 2014] [error]     self.__dict__["_state_event"] = gevent.hub.get_hub().loop.io(
[Wed May 28 11:24:03 2014] [error]   File "/usr/lib/python2.7/dist-packages/gevent/hub.py", line 135, in get_hub
[Wed May 28 11:24:03 2014] [error]     raise NotImplementedError('gevent is only usable from a single thread')
[Wed May 28 11:24:03 2014] [error] NotImplementedError: gevent is only usable from a single thread

经过一番研究后我发现: - gevent与Apache的多线程工作者模型不兼容

1 个答案:

答案 0 :(得分:2)

最后我开始工作了。

import zerorpc
import gevent
from subscrclass import StrategyStateSubscriber
strategy_state_subscriber = StrategyStateSubscriber()
machine_ip = "127.0.0.1"
port = "5555"
end_point = "tcp://" + machine_ip + ":" + port

strategy_state_subscriber = zerorpc.Subscriber(strategy_state_subscriber)

strategy_state_subscriber.connect(end_point)
gevent.spawn(strategy_state_subscriber.run)
gevent.sleep(5) # This line was added

带有子驱动程序调用的原始代码以产生它的方式结束,但实际上并没有给代码做任何事情的机会。

如果我添加了gevent.sleep(5),则协同程序有机会运行5秒钟并且出现打印件。

请务必使用gevent次调用,简单time.sleep(5)无法正常工作,因为它阻止了一个,协同程序没有机会说一句话或运行一行代码。

使用PyCharm IDE我可以想象,你要么有类似的线存在,要么你“慢慢”执行动作,它有机会运行。但这是纯粹的猜测 - 重要的是在代码退出之前为代码提供运行协同程序的机会。

完整示例(没有Flask部分)

这是完整的可运行样本

subscrclass.py

此课程实际上会接收来自发布商的电话。重要的是:

  • 名称为update_strategy_state
  • 有2个参数

这就是:

from datetime import datetime

class StrategyStateSubscriber():
    def update_strategy_state(self, strategy_id, state):
        print datetime.strftime(datetime.now(), "%H:%M:%S"), state

pub.py

这是出版商。

它不会导入任何东西来获取StrategyStateSubscriber,它只会创建对某个远程订阅者的调用,该远程订阅者可能实现了一个名为update_strategy_state的方法,其中包含两个参数。

import gevent
import zerorpc

publisher = zerorpc.Publisher()
publisher.bind("tcp://0.0.0.0:5555")

for a in xrange(0, 1000):
    publisher.update_strategy_state(a, [False, a * a, 3 * a, a % 20, a % 50])
    gevent.sleep(1 if a < 50 else 2)

client.py

最后,我们来到客户,订阅已发布的调用并将其传递给在类StrategySateSubscriber上实现的相关方法(由发布者决定)

import zerorpc
import gevent
from subscrclass import StrategyStateSubscriber

strategy_state_subscriber = zerorpc.Subscriber(StrategyStateSubscriber())
strategy_state_subscriber.connect("tcp://127.0.0.1:5555")
gevent.spawn(strategy_state_subscriber.run)
gevent.sleep(5)

允许生成的进程运行很重要,我们在这里调用gevent.sleep(5),其他调用或非阻塞I / 0操作也可以提供帮助。

运行代码

在第一个控制台中启动发布者:

$ python pub.py

在第二个控制台中,启动客户端:

$ python client.py 
22:30:06 [False, 16, 12, 4, 4]
22:30:07 [False, 25, 15, 5, 5]
22:30:08 [False, 36, 18, 6, 6]
22:30:09 [False, 49, 21, 7, 7]
22:30:10 [False, 64, 24, 8, 8]

结论

  • zerorpc变成了非常强大的工具
  • 有了产生过程,程序员有时会忘记给代码一个运行的机会。这就是原因。
  • 如果Flask中的网页应该快速返回,使用请求/响应(远程过程调用)而不是休眠来获取一些数据会更快。
  • 如果策略状态是长期(例如通过WebSockets)提供给客户端,则发布/订阅消息传递模式最适合。