Tornado Web与线程

4 投票
1 回答
5859 浏览
提问于 2025-04-17 04:44

我刚接触Tornado和Python线程。我想实现的目标是这样的:我有一个Tornado网络服务器,它接收用户的请求。我想把一些数据保存在本地,并定期将这些数据批量写入数据库。

import tornado.ioloop
import tornado.web
import threading

# Keep userData locally in memory
UserData = {}

def background(f):
    """
    a threading decorator
    use @background above the function you want to thread
    (run in the background)
    """
    def bg_f(*a, **kw):
        threading.Thread(target=f, args=a, kwargs=kw).start()
    return bg_f

@background
def PostRecentDataToDBThread(iter = -1):
    i = 0
    while iter == -1 or i < iter: 
        #send data to DB
        UserData = {}
        time.sleep(5*60)
        i = i + 1

class AddHandler(tornado.web.RequestHandler):
    def post(self):
        userID = self.get_argument('ui')
        Data = self.get_argument('data')

        UserData[userID] = Data 


if __name__ == "__main__":
    tornado.options.parse_command_line()

    print("start PostRecentDataToDBThread")
    ### Here we start a thread that periodically sends data to the data base.
    ### The thread is called every 5min. 
    PostRecentDataToDBThread(-1)

    print("Started tornado on port: %d" % options.port)

    application = tornado.web.Application([
        (r"/", MainHandler),
        (r"/add", AddHandler)
    ])
    application.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

这样做是否合适呢?我希望尽量减少服务器的阻塞时间。或者我应该使用gevent或者其他什么吗?在Tornado和线程中同时访问UserData会不会出现问题?在这里,数据的一致性不是特别重要,只要服务器不崩溃就行。

1 个回答

7

Tornado 并不是为了和多线程一起使用的。它是基于 epoll 的,这种方式可以在代码的不同部分之间切换。

一般来说,我建议通过消息队列(比如 pika 和 RabbitMQ,它们和 Tornado 配合得很好)把数据发送到单独的工作进程。工作进程可以收集这些数据消息,然后批量写入数据库,或者你可以用这种设置实现其他的数据处理逻辑。

另外,你也可以使用 Redis 和 brukva,这样可以异步地把接收到的数据写入内存数据库,Redis 会根据配置异步地将这些数据写入磁盘。

撰写回答