python高并发web框架_高并发处理框架 Tornado

Tornado是一个可扩展的非阻塞式Web服务器及其相关工具的开源版本。Tornado每秒可以处理上千的连接,对于实时Web服务器来说,Tornado是一个理想的框架。

Tornado介绍

Tornado使用Python编写的一个强大的可扩展Web服务器,在处理高网络流量时表现的足够强健。相比于其它Python网络框架,Tornado的特点很多:

完备的Web框架:与Django、Falsk一样,Tornado也提供URL路由映射、Request上下文、基于模板的页面渲染技术。

高效的网络库:提供异步I/O支持、超时事件处理。

高效的HTTPClient:不仅仅是服务器端框架,Tornado还提供基于异步框架的HTTP客户端。

高效的内部HTTP服务器:Tornado的HTTP服务器与Tornado异步调用紧密结合,可直接用于生产环境。

完备的WebSocket支持:WebSocket是HTML5的一种新标准,实现了浏览器与服务器之间的双向实时通信。

Tornado安装

Tronado已经被配置到PyPI网站中,使用pip命令:pip install tornado即可,如果下载慢,使用国内源即可!基于Python3、Tornado6.0.4

在当今的计算机应用开发中,要做的是减少程序在I/O相关操作中的等待,提高并发程度。同步I/O操作导致请求进程阻塞,直到I/O操作完成;异步I/O操作不导致请求进程阻塞。在Python中,同步I/O可以简单理解为,一个被调用的I/O函数会阻塞调用函数的执行,而异步I/O不会阻塞调用函数的执行。

同步I/O

# Tornado的HTTP客户端

from tornado.httpclient import HTTPClient

def synchronization_wait():

"""

同步I/O操作访问www.e1yu.com,执行速度取决于网络速度和对方服务器响应速度,

只有对www.e1yu.com访问完成并获取到结果,函数才执行完毕

:return: response.body

"""

http_client = HTTPClient()

# 阻塞,直到www.e1yu.com访问完成

response = http_client.fetch("https://www.e1yu.com")

return response.body

print(synchronization_wait())

异步I/O

# Tornado的HTTP客户端

from tornado.httpclient import AsyncHTTPClient

def handle_response(response):

print(response.body)

def asynchronous_wait():

http_client = AsyncHTTPClient()

# 异步访问,http_client.fetch()在调用后立刻返回无需等待实际访问的完成

# 访问完成,AsyncHTTPClient()会调用callable参数指定的函数

http_client.fetch("https://www.e1yu.com", callable(handle_response))

print(asynchronous_wait())

可迭代与迭代器

协程是Tornado中进行异步I/O开发的方法,它使用了Python的关键字yield,yield将调用者挂起和恢复执行。在学习之前,需要了解一下这些概念。

迭代器Iterator

迭代器是访问集合内元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。迭代器不能回退,只能向前迭代!

Python中所有的Sequence(序列)类型簇都是可迭代的。使用iter()方法可以将列表、集合转换为迭代器:

num = [1, 2, 3, 4, 5, 6, 7]

iter_tor = iter(num)

#

print(iter_tor)

迭代器与普通Python对象的区别:迭代器可以调用next()函数获取一个元素,不断调用next()就能逐个访问集合中所有的元素

num = [1, 2, 3, 4, 5, 6, 7]

iter_tor = iter(num)

# 1

print(iter_tor.__next__())

# 2

print(next(iter_tor))

可以一直调用next()函数,直到返会StopIteration异常表示迭代已经完成。其中__next__()和next()函数两者实现效果一样。

定义生成器

迭代器在Python中使用范围很广,一般有两种方式定义迭代器:

实现一个(可迭代对象)Iterable,使用iter()函数获取迭代器。

用yield关键字直接将一个函数转变为迭代器,用这种方式定义的迭代器被称为生成器。

任何一个可迭代对象Iterable都可以通过iter()函数生成一个迭代器。定义一个Iterable类一般可以通过为其实现__iter__()和__next()俩个成员方法实现:

class MyIterable():

def __init__(self):

self.data = [1, 2, 3, 4]

self.step = 0

# 返回一个实现了__next__()的对象

def __iter__(self):

return self

# 返回一个元素,没有元素抛出异常

def __next__(self):

if self.step >= len(self.data):

raise StopIteration

data = self.data[self.step]

print('index:{0} call of next()'.format(self.step))

self.step += 1

return data

for i in MyIterable():

print(i)

使用生成器可以简化代码,调用任何定义中包含yield关键字的函数都会不执行该函数,而会获得一个对应该函数的生成器。

def MyIterator():

# 定义一个迭代器函数

for k, v in enumerate([1, 2, 3, 4]):

print('index:{0} call of next()'.format(k))

# 用yield返回一个元素

yield v

for i in MyIterator():

print(i)

异步和协程

异步上面简单介绍过,接下来要说的是协程。Tornado协程可以开发出类似同步代码的异步行为。编写一个简单的协程函数:

# 引入协程库gen

from tornado import gen

from tornado.httpclient import AsyncHTTPClient

# 使用gen.coroutine装饰器,声明一个协程函数

@gen.coroutine

def coroutine_wait():

http_client = AsyncHTTPClient()

response = yield http_client.fetch("https://www.e1yu.com")

print(response.body)

Tornado协程基于Python的yield关键字,所以你不能直接像调用函数呢样调用协程。协程函数可以通过以下三种方式调用:

在本身是协程的函数内通过yield关键字调用

在IOLoop没有启动时,通过IOLoop的run_sync()函数调用

在IOLoop已经启动时,通过IOLoop的spawn_callback()函数调用

1.通过协程函数调用协程函数

# 使用gen.coroutine装饰器,声明一个协程函数

@gen.coroutine

def outer_coroutine():

print('start to call a coroutine')

yield coroutine_wait()

print('end of outer_coroutine')

outer_coroutine()

2.在IOLoop没有启动时,通过IOLoop的run_sync()函数调用

IOLoop是Tornado的主事件循环对象,Tornado程序通过监听外部客户端的访问请求,并执行相应的操作。当程序没有进入IOLoop的running状态时,可以通过run_sync()函数调用协程函数:

from tornado.ioloop import IOLoop

def func_sync():

print('start to call a coroutine')

IOLoop.current().run_sync(lambda: coroutine_wait())

print('end of outer_coroutine')

func_sync()

在普通函数中使用run_sync()函数调用,经过lambda封装的协程函数。run_sync()函数将阻塞当前函数的执行,直到被调用的协程执行完成。

Tornado要求协程函数在IOLoop的running状态中才能被调用,只不过run_sync()函数自动完成了启动、停止IOLoop的步骤,它的实现逻辑为:启动IOLoop——调用lambda封装的协程函数——停止IOLoop。

3.在IOLoop已经启动时,通过IOLoop的spawn_callback()函数调用

当Tornado程序处于running状态时的协程函数调用:

from tornado.ioloop import IOLoop

def func_sync():

print('start to call a coroutine')

IOLoop.current().spawn_callback(lambda: coroutine_wait)

print('end of outer_coroutine')

func_sync()

spawn_callback()函数将不会等待被调用协程执行完成,所以该普通函数运行只会打印两个print的结果,coroutine_wait()本身会由IOLoop在合适的时机调用。

IOLoop的spawn_callback()函数没有提供获取协程函数调用的返回值的方法,所以只能使用spawn_callback()调用没有返回值的协程函数。

协程中调用阻塞函数

协程中调用阻塞函数,会影响协程本身的性能。Tornado提供了在协程中利用线程池调度阻塞函数,不影响协程本身继续执行。

from tornado import gen

from concurrent.futures import ThreadPoolExecutor

# 实例化两个线程的线程池

thread_pool = ThreadPoolExecutor(2)

def my_sleep(count):

import time

for i in range(count):

time.sleep(1)

@gen.coroutine

def call_block():

print('start to call_block')

# 调用阻塞函数

yield thread_pool.submit(my_sleep, 10)

print('end of call_block')

# 调用没有返回值的协程函数

call_block()

在协程中等待多个异步调用

Tornado允许在协程中使用一个yield关键字等待多个异步调用,只需要把这些调用列表list或字典dictionary的方式传递给yield即可

from tornado.httpclient import AsyncHTTPClient

from tornado import gen

# 列表方式

@gen.coroutine

def coroutine_list():

http_client = AsyncHTTPClient()

# 只有在列表中的所有调用都执行完成,yield才会返回并继续执行

list_response = yield [http_client.fetch('https://www.e1yu.com'),

http_client.fetch('https://www.baidu.com'),

http_client.fetch('https://www.qq.com')

]

for response in list_response:

print(response)

# 字典方式

@gen.coroutine

def coroutine_dict():

http_client = AsyncHTTPClient()

# 只有在列表中的所有调用都执行完成,yield才会返回并继续执行

dict_response = yield {"e1yu": http_client.fetch('https://www.e1yu.com'),

"baidu": http_client.fetch('https://www.baidu.com'),

"qq": http_client.fetch('https://www.qq.com')

}

print(dict_response['e1yu'].body)

未经允许不得转载:作者:鳄鱼君,

转载或复制请以 超链接形式 并注明出处 鳄鱼君。

原文地址:《高并发处理框架 Tornado》 发布于2020-07-12

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值