【问题标题】:Using tornado ioloop for loading big python pickle file into memory使用 tornado ioloop 将大 python 泡菜文件加载到内存中
【发布时间】:2018-03-09 07:36:35
【问题描述】:

我正在构建一个测试服务器,当一个端点被命中时,它会加载一个巨大的 pickle 文件(大约需要 30 秒)。我的目标是在龙卷风网络服务器作为单独的线程启动时,更新它以在后台将泡菜作为 python 对象加载到内存中。因此,当端点被命中时,它要么在内存中找到它,要么等待线程完成加载。这样会加快启动速度。

我在这里寻求一些关于添加异步以使此操作正常工作的最佳方法的建议。

my_server.py

    import tornado.ioloop
    import tornado.web

    from my_class import MyClass

    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            m = MyClass.get_foobar_object_by_name('foobar')
            self.write("Hello, world")

    def make_app():
        return tornado.web.Application([
            (r"/", MainHandler),
        ])

    if __name__ == "__main__":
        app = make_app()
        app.listen(8888)
        MyClass.load()  # takes 30s to load
        tornado.ioloop.IOLoop.current().start()

my_class.py

    class MyClass(object):
        pickle_path = '/opt/some/path/big_file.pickle'
        foobar_map = None

        @staticmethod
        def load():
            # this step takes about 30s to load
            MyClass.foobar_map = pickle.load(open(local_path, 'rb'))

        @staticmethod
        def get_foobar_object_by_name(foobar_name):
            if MyClass.foobar_map is None:
                MyClass.load()
            return MyClass.foobar_map.get(foobar_name)

【问题讨论】:

    标签: python asynchronous tornado


    【解决方案1】:

    pickle 模块有一个同步接口,所以异步运行它的唯一方法是在另一个线程上运行它。在 Tornado 5.0 中使用新的IOLoop.run_in_executor 接口:

    from tornado.ioloop import IOLoop
    from tornado.web import RequestHandler
    from tornado.locks import Lock
    
    class MyClass:
        lock = Lock()
    
        @staticmethod
        async def load():
            async with MyClass.lock():
                # Check again inside the lock to make sure we only do this once. 
                if MyClass.foobar_map is None:
                    MyClass.foobar_map = await IOLoop.current().run_in_executor(None, pickle.load, open(local_path, 'rb'))
    
        @staticmethod
        async def get_foobar_object_by_name(foobar_name):
            if MyClass.foobar_map is None:
                await MyClass.load()
            return MyClass.foobar_map.get(foobar_name)
    
    class MainHandler(RequestHandler):
        async def get(self):
            m = await MyClass.get_foobar_object_by_name('foobar')
            self.write("Hello, world")
    

    请注意async 具有传染性:任何调用async 函数的东西也必须是async 并使用await

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-26
      • 2021-05-12
      • 2014-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      相关资源
      最近更新 更多