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

2018-04-10 09:35:50 +08:00
 Danic

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 天,没有好的解决方案,因此来这里求指点~ 谢谢大家啦~~~

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

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

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

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

另外开发一个进程专门来处理外部调用的请求,收到请求后从数据库读取配置,PUB 配置到 redis,所有 tornado 进程 SUB,收到配置后更新 A
wcsjtu
2018-04-10 23:59:43 +08:00
试试 redis 的发布者 /订阅者模型, 反正同步的 redis 驱动的速度也非常快。。。
Danic
2018-04-11 09:21:57 +08:00
@lzlzlzlz 我现在是用 tornado.process.fork_process(4) 这种方式创建进程的,你说的这种方法我今天试试看~
Danic
2018-04-11 09:23:41 +08:00
@zhu327 是的,问题就是这个样子,我去实践一下你的方法,谢谢啦~
Danic
2018-04-11 09:23:51 +08:00
@wcsjtu 恩恩
petelin
2018-04-11 13:02:51 +08:00
我想说要是用 go 的话 这就不是问题了, 有 channel
petelin
2018-04-11 14:33:18 +08:00
还可以通过 tcp 来通信, 这种方法就是省了 Redis
sujin190
2018-04-11 20:36:03 +08:00
这个变量 A 在 fork 之前用 multiprocessing 创建成共享内存变量就行了啊,这样 fork 之后任何一个字进程修改了变量的值,其他进程都会同步读取到新的值,只是每次访问共享变量比访问普通变量要慢很多
bookding0
2018-04-12 16:08:31 +08:00
你说的用 tornado 创建多个进程指的是 fork 出多个 tornado application 的子进程,还是说直接跑多个进程?
Danic
2018-04-13 10:34:25 +08:00
@bookding0 我是直接通过 tornado.process.fork_process(4) 这种方式创建多个子进程的。
Danic
2018-04-13 10:35:45 +08:00
@sujin190 还有这种操作的吗,是用 multiprocessing 的哪个方法创建内存变量的
Danic
2018-04-13 10:39:47 +08:00
@petelin 这样会不会导致效率变低呀,网络请求的耗时感觉会长一点,算法那边是要求速度能快一点就好,感觉用一个共享的内存变量应该效率会高一点,但是多进程处理同一个变量会出好多问题。
Danic
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
2018-04-13 14:20:54 +08:00
@Danic #12 multiprocessing.Array multiprocessing.Value 创建的都是共享内存啊,fork 之后都是多个子进程共享的
Danic
2018-04-13 14:51:55 +08:00
@sujin190 哦哦,学习了
petelin
2018-08-02 15:24:46 +08:00
@Danic 本地 socket.没有网络消耗, 还有命名管道, 速度差不多

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/445540

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX