第十章 tornado

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他

第十章 tornado

1. tornado中的gen.coroutine的作用?

在Tornado框架中,`gen.coroutine` 是用于定义协程(coroutine)的装饰器。
协程是一种轻量级的并发编程的方式,它允许你写异步的代码,
但看起来像是同步的。使用 `gen.coroutine` 装饰器可以将普通的函数转换为协程。

在Tornado中,`gen.coroutine` 的作用有几个方面:
1. **异步操作的简化:** 
	允许在协程中使用 `yield` 关键字来暂时释放控制权,而不会阻塞整个应用程序。
	当在协程中遇到一个异步操作(比如异步的网络请求、数据库查询等)时,
	可以使用 `yield` 关键字将控制权交还给事件循环,等待异步操作完成后再继续执行。

   from tornado import gen, ioloop

   @gen.coroutine
   def async_function():
       result = yield some_async_operation()
       # 继续执行其他操作

   ioloop.IOLoop.current().run_sync(async_function)


2. **异常处理:** `
	gen.coroutine` 会自动捕获协程中的异常,并将其传递给协程的调用者。
	这样可以更方便地处理异步操作可能引发的异常。
   @gen.coroutine
   def async_function():
       try:
           result = yield some_async_operation()
           # 继续执行其他操作
       except SomeException as e:
           # 处理异常

3. **返回 Future 对象:** 
	使用 `gen.coroutine` 装饰器的函数会返回一个 `Future` 对象,
	可以通过这个对象获取协程的执行结果或注册回调函数。

   @gen.coroutine
   def async_function():
       result = yield some_async_operation()
       raise gen.Return(result)

总的来说,`gen.coroutine` 使得在Tornado中编写异步代码更加简单和清晰。
在Python 3.5及以后版本中,可以使用 `async/await` 关键字替代 `gen.coroutine/yield`,但在早期版本中,`gen.coroutine` 是一种常用的异步编程方式。

2. tornado框架中Future对象的作用?

在Tornado框架中,`Future` 对象是一种用于异步编程的抽象,它代表了一个尚未完成的操作的结果。
`Future` 对象用于处理异步函数的返回值,允许以非阻塞的方式等待异步操作完成。

以下是`Future`对象的主要作用:
1. **异步操作的结果容器:** 
	`Future` 用于存储异步操作的结果。当一个异步操作开始时,它会返回一个 `Future` 对象,
	该对象最终会在异步操作完成时被设置为相应的结果或异常。
   from tornado.concurrent import Future

   def async_operation():
       future = Future()
       # 异步操作完成后设置结果
       # future.set_result(result)
       # 或者在出现异常时设置异常信息
       # future.set_exception(exception)
       return future


2. **等待异步操作完成:** 
	可以使用 `yield` 或 `add_done_callback` 来等待 `Future` 对象的完成。
	这样可以在异步操作完成后继续执行后续的代码。

   from tornado import gen

   @gen.coroutine
   def async_function():
       future = async_operation()
       result = yield future  # 等待异步操作完成
       # 处理结果

   或者使用 `add_done_callback` 注册回调函数:
   def callback_func(future):
       # 处理异步操作完成后的结果

   future = async_operation()
   future.add_done_callback(callback_func)


3. **异常处理:** 
	如果异步操作出现异常,可以在 `Future` 对象上设置异常信息。
	在等待 `Future` 完成时,可以通过捕获异常来处理异步操作可能引发的错误。

   @gen.coroutine
   def async_function():
       try:
           result = yield async_operation()
           # 处理结果
       except Exception as e:


4. **链式调用:** 
	可以通过 `add_done_callback` 注册多个回调函数,形成链式调用,以处理异步操作的多个阶段。

   def callback1(future):
       # 处理第一个阶段的结果
       future2 = async_operation2()
       future2.add_done_callback(callback2)

   def callback2(future):
       # 处理第二个阶段的结果

   future = async_operation1()
   future.add_done_callback(callback1)


总体而言,`Future` 对象是Tornado中处理异步操作结果的一种重要机制,它使得异步编程变得更加可控和灵活。

3. tornado框架中如何编写webSocket程序?

在Tornado框架中,编写WebSocket程序涉及到创建一个`WebSocketHandler`来处理WebSocket连接和消息。

以下是一个简单的例子,演示了如何在Tornado中编写WebSocket程序:
import tornado.ioloop
import tornado.web
import tornado.websocket

class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket连接已打开")

    def on_message(self, message):
        print(f"收到消息:{message}")
        self.write_message(f"你发送的消息是:{message}")

    def on_close(self):
        print("WebSocket连接已关闭")

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, World!")

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

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("应用已启动,监听端口8888")
    tornado.ioloop.IOLoop.current().start()


在这个例子中,`WebSocketHandler` 类继承自 `tornado.websocket.WebSocketHandler`,

并且覆盖了三个方法:
- `open(self)`: 当WebSocket连接建立时被调用。
- `on_message(self, message)`: 当接收到WebSocket消息时被调用。
- `on_close(self)`: 当WebSocket连接关闭时被调用。

在`make_app` 函数中,我们将 `"/websocket"` 路由映射到 `WebSocketHandler` 类,
使得所有以该路径为目标的WebSocket连接都由 `WebSocketHandler` 处理。

在`on_message` 方法中,我们通过 `self.write_message` 方法向客户端发送消息。
在这个例子中,它简单地将接收到的消息返回给客户端。

为了运行这个WebSocket应用程序,你需要在终端中执行脚本,并通过WebSocket客户端连接到 
`ws://localhost:8888/websocket`。你可以使用浏览器中的JavaScript WebSocket API,
也可以使用其他WebSocket客户端工具。

这只是一个简单的例子,Tornado提供了更多高级的WebSocket功能,
比如支持WebSocket的异步处理和WebSocket的关闭帧处理等。

4. tornado中静态文件是如何处理的?

在Tornado中,静态文件的处理是通过`StaticFileHandler`来完成的。
`StaticFileHandler`是Tornado框架中用于处理静态文件的专用处理器。
它可以处理诸如CSS、JavaScript、图像等静态文件,并且具有缓存控制等功能。

以下是一个简单的例子,演示了如何在Tornado中处理静态文件:
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, World!")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/static/(.*)", tornado.web.StaticFileHandler, {"path": "static"}),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("应用已启动,监听端口8888")
    tornado.ioloop.IOLoop.current().start()

在这个例子中,我们创建了一个`StaticFileHandler`,并将其映射到路径`/static/(.*)`,
同时指定了`{"path": "static"}`参数。这表示Tornado会在运行时查找静态文件时,
从当前工作目录下的`static`目录中查找。

- `(r"/static/(.*)", tornado.web.StaticFileHandler, 
	{"path": "static"})`: 这个路由规则将匹配所有以`/static/`开头的URL,
	并且`(.*)`捕获了后面的路径,将其传递给`StaticFileHandler`进行处理。

在上述例子中,假设你的项目结构如下:
project/
|-- app.py
|-- static/
|   |-- style.css

如果你访问 `http://localhost:8888/static/style.css`,Tornado将会在`static`目录下
寻找`style.css`文件并将其返回给浏览器。请确保Tornado应用程序的运行目录(即执行`app.py`
的目录)下存在`static`目录,并在`static`目录中包含了你要提供的静态文件。

此外,你还可以使用Tornado提供的`static_url`和`static_path`方法来生成静态文件的URL和
本地路径。这样可以在应用程序的其他地方动态生成静态文件的URL,而不需要硬编码路径。

5. tornado操作MySQL使用的模块?

在Tornado中,你可以使用异步的MySQL客户端库来进行数据库操作。
一种常用的库是`tornado_mysql`,它提供了对MySQL数据库的异步支持。
你可以使用类似于Tornado的协程(coroutine)的方式进行异步数据库查询。

以下是一个简单的例子,演示了如何在Tornado中使用`tornado_mysql`进行MySQL数据库操作:
首先,你需要安装`tornado_mysql`:
pip install tornado_mysql

然后,可以使用以下代码在Tornado中进行MySQL数据库操作:
import tornado.ioloop
import tornado.web
import tornado_mysql

from tornado import gen

class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        # 异步执行数据库查询
        result = await self.db_query("SELECT * FROM your_table")
        
        self.write(f"Database Result: {result}")

    @gen.coroutine
    def db_query(self, query):
        # 使用tornado_mysql进行数据库查询
        cursor = yield tornado_mysql.cursors.DictCursor(self.application.db_conn_pool)
        yield cursor.execute(query)
        result = cursor.fetchall()
        cursor.close()
        raise gen.Return(result)

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

if __name__ == "__main__":
    app = make_app()
    
    # 在应用启动时创建数据库连接池
    app.db_conn_pool = tornado_mysql.ConnectionPool(
        host="your_mysql_host",
        user="your_mysql_user",
        password="your_mysql_password",
        database="your_mysql_database",
    )
    
    app.listen(8888)
    print("应用已启动,监听端口8888")
    tornado.ioloop.IOLoop.current().start()


请替换上述代码中的`your_mysql_host`、`your_mysql_user`、`your_mysql_password`、
`your_mysql_database`和`your_table`为你实际的MySQL数据库信息。

这个例子中,我们使用了`ConnectionPool`来创建MySQL数据库连接池,以支持异步操作。
在`MainHandler`中,通过调用`self.db_query`进行数据库查询,实现了异步的数据库操作。

需要注意的是,这只是一个简单的例子。在实际的应用中,你可能需要更好的错误处理、连接池管理、
以及更复杂的SQL查询。确保适应你的具体需求。

6. tornado操作redis使用的模块?

在Tornado中,你可以使用`toro-redis`模块进行对Redis数据库的操作。
 `toro-redis`是Tornado的一个异步Redis客户端库,它允许你以异步的方式执行Redis操作。
 
首先,你需要安装`toro-redis`:
pip install toro-redis

然后,你可以使用以下代码在Tornado中进行Redis数据库操作:
import tornado.ioloop
import tornado.web
import toro

class MainHandler(tornado.web.RequestHandler):
    async def get(self):
        # 异步执行Redis查询
        result = await self.redis_get("my_key")
        
        self.write(f"Redis Result: {result}")

    async def redis_get(self, key):
        # 使用toro-redis进行Redis查询
        result = await self.application.redis.get(key)
        return result

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

if __name__ == "__main__":
    app = make_app()
    
    # 在应用启动时创建Redis连接
    app.redis = toro.redis.Client()
    app.redis.connect(host='your_redis_host', port=6379, db=0)
    
    app.listen(8888)
    print("应用已启动,监听端口8888")
    tornado.ioloop.IOLoop.current().start()

请替换上述代码中的`your_redis_host`为你实际的Redis数据库主机地址。

在这个例子中,我们创建了一个`toro.redis.Client`实例来连接到Redis数据库。
在`MainHandler`中,通过调用`self.redis_get`进行Redis查询,实现了异步的Redis操作。

需要注意的是,这只是一个简单的例子。在实际的应用中,你可能需要更好的错误处理、连接池管理,
以及更复杂的Redis操作。确保适应你的具体需求。

你可能感兴趣的:(python常见题2,tornado,python)