如何为基于Tornado的应用的每个子进程初始化不同对象?
为Tornado每个子进程初始化独立MyClass实例的解决方案
先澄清:实例ID相同不代表是同一个实例
调用tornado.process.fork_processes(4)后,操作系统会复制父进程的地址空间生成4个独立子进程。每个子进程都会单独执行obj = MyClass(),这些实例在物理内存中完全独立。你看到的id(obj)相同,只是因为每个进程的虚拟地址空间是隔离的,同一个虚拟地址在不同进程里指向不同的物理内存块——这个ID仅在单个进程内有效,不能用来判断跨进程的实例是否相同。
验证实例独立性的方法
给MyClass加一个唯一标识属性,就能直观区分不同子进程的实例:
import os import random class MyClass: def __init__(self): self.unique_id = random.randint(1, 100000) self.pid = os.getpid()
然后修改打印语句:
print(f"PID: {os.getpid()}, Obj ID: {id(obj)}, Unique ID: {obj.unique_id}")
运行后会看到每个子进程的Unique ID都不一样,这就证明实例是完全独立的。
确保每个子进程初始化不同实例的正确写法
你的代码其实已经实现了需求——因为obj = MyClass()是在fork_processes之后执行的,每个子进程都会独立创建新实例。需要注意的是:
- 绝对不要在
fork_processes之前创建MyClass实例或其他带状态的对象,否则子进程会复制这些对象的状态,可能导致文件句柄、网络连接等资源被意外共享。 - 所有子进程专属的初始化逻辑,必须放在
fork_processes调用之后执行。
优化后的完整代码
import os import asyncio import tornado.web import tornado.httpserver import tornado.netutil import tornado.process class PromptHandler(tornado.web.RequestHandler): def initialize(self, obj): self.obj = obj async def get(self): self.write(f"处理请求的进程ID: {os.getpid()}, 实例唯一标识: {self.obj.unique_id}") def make_app(obj): return tornado.web.Application([(r'/index', PromptHandler, {"obj": obj})]) async def post_fork_main(obj): app = make_app(obj) server = tornado.httpserver.HTTPServer(app) server.add_sockets(sockets) await asyncio.Event().wait() class MyClass: def __init__(self): # 用进程ID+随机字符串生成唯一标识 self.unique_id = f"{os.getpid()}_{os.urandom(4).hex()}" if __name__ == '__main__': sockets = tornado.netutil.bind_sockets(8080) # 先fork进程,再初始化实例 tornado.process.fork_processes(4) obj = MyClass() print(f"PID: {os.getpid()}, Obj内存地址: {id(obj)}, 实例唯一标识: {obj.unique_id}") asyncio.run(post_fork_main(obj))
启动服务后访问http://localhost:8080/index,多次刷新会看到不同的实例唯一标识,说明请求被不同子进程处理,每个子进程的MyClass实例都是独立的。
内容的提问来源于stack exchange,提问作者taichi_tiger
相关产品推荐
相关产品推荐

