V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Danic
V2EX  ›  Python

[Python2.7] tornado 多个子进程间的通信

  •  
  •   Danic · 2018-04-10 09:35:50 +08:00 · 4964 次点击
    这是一个创建于 2445 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Python 版本:2.7

    现在需要利用 tornado 实现这个样子的一个功能:

         1.利用 tornado 创建多个进程。

         2.进程内写有 从数据库读取配置信息 的方法,读取出来的配置信息将会存储在进程中的一个 A 变量中。

         3.进程内写有 根据配置信息做出对应的操作 的方法,其中配置信息是从 A 变量中取出的。

         4.因为连接数据库比较耗时,所以将配置信息存在变量中,以供下次更快得获取配置信息。数据库中的配置信息会被修改(但频次不确定,有可能半天一次,有可能一天一次,所以不准备用定时任务同步配置信息),当其他服务修改完配置信息后会调用 从数据库读取配置信息 的接口方法。

    目前遇到的问题:

    假设有 10 个进程在跑,在其他服务修改完配置信息后,其发送的请求只有一次,只会被一个进程竞争到从而调用 从数据库读取配置信息 的方法,但是剩下的 9 个是不会调用该方法的。由于是利用多进程进行处理,所以每个进程的 A 变量是不同的,因此会造成一个进程的 A 变量存放的是半小时前的配置信息,但是另一个进程的 A 变量存放的是刚刚更新的配置信息。 有什么办法可以让每个进程的 A 变量都同步起来呢?

    尝试过的解决方案:

         1.采用管道( Pipe )通信,在一个进程接收到 从数据库读取配置信息 的调用请求时,通过管道向其他进程发送消息,使他们都调用一次 从数据库读取配置信息 的方法。但是管道通信貌似是阻塞的,而且发出来的一次消息,被消费后就不存在的,也就是说只有一个进程可以收到这条通知。无效~

         2.事件方式,灵感来自于 ioloop.add_handler()。但是 google 了一下,貌似只有 ioloop 有这个方法,不知道可不可以对进程添加一个监听事件。

    尝试了 2 天,没有好的解决方案,因此来这里求指点~ 谢谢大家啦~~~

    17 条回复    2018-08-02 15:24:46 +08:00
    lzlzlzlz
        1
    lzlzlzlz  
       2018-04-10 16:38:33 +08:00
    不知道你是怎么来创建多进程的. 如果是用 multiprocessing 话, 那么里面有 manager 这个模块, 其作用是进程间共享数据.
    zhu327
        2
    zhu327  
       2018-04-10 18:55:03 +08:00   ❤️ 1
    从描述来看,问题点是不是这样的:

    1. 需要在 tornado 进程里面更新配置 A, 更新是通过外部调用一个请求过来的
    2. 当前只能请求一次,所以只有一个进程的配置被更新了

    如果是上面的问题的话,你需要的应该是一种订阅通知的机制,某个事件发生的时候,需要通知到所有的进程

    所以建议考虑用 redis 的 PUB/SUB 来实现, etcd 这种专门用来做配置管理的也很合适

    另外开发一个进程专门来处理外部调用的请求,收到请求后从数据库读取配置,PUB 配置到 redis,所有 tornado 进程 SUB,收到配置后更新 A
    wcsjtu
        3
    wcsjtu  
       2018-04-10 23:59:43 +08:00
    试试 redis 的发布者 /订阅者模型, 反正同步的 redis 驱动的速度也非常快。。。
    Danic
        4
    Danic  
    OP
       2018-04-11 09:21:57 +08:00
    @lzlzlzlz 我现在是用 tornado.process.fork_process(4) 这种方式创建进程的,你说的这种方法我今天试试看~
    Danic
        5
    Danic  
    OP
       2018-04-11 09:23:41 +08:00
    @zhu327 是的,问题就是这个样子,我去实践一下你的方法,谢谢啦~
    Danic
        6
    Danic  
    OP
       2018-04-11 09:23:51 +08:00
    @wcsjtu 恩恩
    petelin
        7
    petelin  
       2018-04-11 13:02:51 +08:00
    我想说要是用 go 的话 这就不是问题了, 有 channel
    petelin
        8
    petelin  
       2018-04-11 14:33:18 +08:00
    还可以通过 tcp 来通信, 这种方法就是省了 Redis
    sujin190
        9
    sujin190  
       2018-04-11 20:36:03 +08:00
    这个变量 A 在 fork 之前用 multiprocessing 创建成共享内存变量就行了啊,这样 fork 之后任何一个字进程修改了变量的值,其他进程都会同步读取到新的值,只是每次访问共享变量比访问普通变量要慢很多
    bookding0
        10
    bookding0  
       2018-04-12 16:08:31 +08:00
    你说的用 tornado 创建多个进程指的是 fork 出多个 tornado application 的子进程,还是说直接跑多个进程?
    Danic
        11
    Danic  
    OP
       2018-04-13 10:34:25 +08:00
    @bookding0 我是直接通过 tornado.process.fork_process(4) 这种方式创建多个子进程的。
    Danic
        12
    Danic  
    OP
       2018-04-13 10:35:45 +08:00
    @sujin190 还有这种操作的吗,是用 multiprocessing 的哪个方法创建内存变量的
    Danic
        13
    Danic  
    OP
       2018-04-13 10:39:47 +08:00
    @petelin 这样会不会导致效率变低呀,网络请求的耗时感觉会长一点,算法那边是要求速度能快一点就好,感觉用一个共享的内存变量应该效率会高一点,但是多进程处理同一个变量会出好多问题。
    Danic
        14
    Danic  
    OP
       2018-04-13 10:58:48 +08:00
    开始是考虑了 @zhu327 所述的 redis 中 PUB/SUB 模式,但是我在网上的资料找到是是需要用 redis 环境的,目前服务器不准备配置 redis,所以这个方案先暂时放到后续考虑。
    后面我想了一下,与其多个进程维护各自的变量,不如让多个进程去维护一个共享的变量,这样管理也会方便很多,也不会出现多个进程变量不一致的情况。我采用了[https://docs.python.org/2/library/multiprocessing.html#managers]中,第 16.6.1.4. 节的 Sharing state between processes 下的 Server Process 方法,利用 multiprocessing 创建一个服务进程,利用该进程去维护一个变量,然后在其他进程中的操作也会同步到服务进程的变量中。
    可是用上述的 Server Process 方法,貌似会遇到锁的问题,我得再研究研究。
    先谢过大家了~~~
    sujin190
        15
    sujin190  
       2018-04-13 14:20:54 +08:00
    @Danic #12 multiprocessing.Array multiprocessing.Value 创建的都是共享内存啊,fork 之后都是多个子进程共享的
    Danic
        16
    Danic  
    OP
       2018-04-13 14:51:55 +08:00
    @sujin190 哦哦,学习了
    petelin
        17
    petelin  
       2018-08-02 15:24:46 +08:00
    @Danic 本地 socket.没有网络消耗, 还有命名管道, 速度差不多
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5362 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 08:06 · PVG 16:06 · LAX 00:06 · JFK 03:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.