python 异步原理_了解python异步web框架原理

本文介绍了Python中的异步编程原理,从同步方式的socket编程开始,逐步过渡到异步I/O机制。通过Selectors模块,展示了如何使用BaseSelector和事件循环(EventLoop)来实现非阻塞的读写操作。文章还详细解释了如何构建一个基于selectors的TCPEchoServer,该服务器可以处理多个并发连接,通过注册和回调函数实现了异步处理客户端请求。最后,给出了启动服务器的代码示例,供读者进行压力测试。
摘要由CSDN通过智能技术生成

今天给大家介绍下使用

先看下同步的方式,定义一个socket对象,绑定完端口后开始监听,在一个无限循环内接收到的数据,经过处理后返回给客户端,并通过with关闭。

import socket

HOST ='localhost'

PORT=8888

with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:

s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

s.bind((HOST,PORT))

s.listen(128)

while True:

conn,addr = s.accept()

print('Connected from:',addr)

with conn:

while 1:

data = conn.recv(1024)

if not data:

break

conn.sendall(data)

我们可以使用浏览器直接测试这个服务器,就可以看到浏览器收到服务器返回的数据。

下面开始异步的讲解,建议大家可以直接去官网的链接Selectors模块看它的说明。其实大部分的异步框架都是通过系统提供的异步I/O机制实现的。

简单了解下selectors:通过它我们可以同时监听多个socket连接,并且注册一个回调函数,这样就能实现非阻塞的读写。我们可以使用BaseSelector来根据平台自动选择最合适的机制。我们只要通过几个几个简单的函数就可以完成对它的使用register方法注册一个socket对象,这里是官网的定义:

abstractmethod register(fileobj, events, data=None)

Register a file object for selection, monitoring it for I/O events.

还有与之相对的unregister方法。接下来是select来实现事件的循环。官网首页有一个使用的例子,下面就这个例子我们扩展开来具体看看select的使用。

定义一个EventLoop类:

class EventLoop:

def __init__(self,selector=None):

if selector is None:

selector= selectors.DefaultSelector()

self.selector=selector

def run_forever(self):

while True:

events =self.selector.select()

for key,mask in events:

if mask == selectors.EVENT_READ:

callback = key.data

callback(key.fileobj)

else:

callback,msg = key.data

callback(key.fileobj,msg)

在这个类里的初始化中我们使用DefaultSelector新建了一个selectors的对象,然后通过run_forever的函数来执行事件循环。

接着再定义一个TCPEchoServer的类:

class TCPEchoServer:

def __init__(self,host,port,loop):

self.host = host

self.port = port

self._loop = loop

self.s = socket.socket()

def run(self):

self.s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

self.s.bind(self.host,self.port)

self.s.listen(128)

self.s.setblocking(False)

self._loop.selector.register(self.s,selectors.EVENT_READ,selef._accept)

self._loop.run_forever()

在初始化里,我们接受host地址和端口还有刚才定义的EventLoop实例;

在run函数里开始对socket进行各种设置:

1.绑定端口

2设置最大监听上限128

3设置非阻塞

4.设置回调函数

5启动事件循环

继续编写回调函数:

def _accept(self,scok):

conn,addr = sock.accept()

print('accepted',conn,'from',addr)

conn.setblocking(False)

self._loop.selector.register(conn,selectors.EVENT_READ,self._on_read)

当受到请求时,我们print一些提示,接着继续注册读事件的回调函数:

def _on_read(self,conn):

msg = conn.recv(1024)

if msg:

print('echoing',repr(msg),'to',conn)

self._loop.selector.modify(conn,selectors.EVENT_WRITE,(self._on_wirte,msg))

else:

print('closing',conn)

self._loop.selector.unregister(conn)

conn.close()

先通过recv方法获取到请求的信息;

1如果请求信息不为空就print到控制台,然后为写事件注册回调函数。

2如果请求为空,则直接关闭连接,并且在事件循环中关闭连接。

写的回调函数:

def _on_wirte(self ,conn,msg):

conn.sendall(msg)

self._loop.selector.modify(conn,selectors.EVENT_READ,self._on_read)

使用sendall将信息发送给客户端,并且使用modify修改为读事件。

这样server就完成了,启动这个server:

event_loop = EventLoop()

echo_server = TCPEchoServer('localhost',8888,event_loop)

echo_server.run()

到此为止就将官网的例子按照class的方式重写完了,大家可以使用压力测试工具批量测试下这个server。

版权所属,如需转载,请注明出处:搜闲鱼

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值