python asyncio原理_Asyncio 原理分析

Asyncio 原理分析

异步io的本质是对系统的基本的异步io函数epoll, selector的封装。 但凡异步必将涉及事件-回调,而裸的事件回调会使代码复杂,比如又要考虑出现异常怎么办,回调中套回调, 回调间数据怎么共享,怎么判断谁触发回调都很麻烦。

asyncio这个库就是使用python的yield这个可以打断保存当前函数的上下文的机制, 封装好了selector 摆脱掉了复杂的回调关系

本篇主要是对参考资料那篇文章的一个笔记 ,原文章很精彩,建议大家看一下

原始的selector

class Client:

def __init__(self):

self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

self.resp = b''

def connect(self):

self.sock.setblocking(False)

try:

self.sock.connect(("127.0.0.1", 5003))

print("sock connection")

except BlockingIOError:

pass

selector.register(self.sock.fileno(), selectors.EVENT_WRITE, self.write)

def read(self, key, mask):

chunk = self.sock.recv(4096)

if chunk:

self.resp = self.resp+chunk

else:

selector.unregister(key) # 这个放着里是一次拿4k数据 如果没拿完就一直监听这个事件

print(self.resp)

return

def write(self, key, mask):

print("start write")

selector.unregister(key)

self.sock.send(b"hello")

print("finish write")

selector.register(key, selectors.EVENT_READ, self.read)

if __name__ == '__main__':

c = Client()

c.connect()

while True:

events = selector.select()

for key, mask in events:

callback = key.data

callback(key.fd, mask)

基本思路就是事件-回调的思路, 先register注册一个写事件,等能触发了用unregister标志认领了事件

使用生成器

Future

我们先设计一个Future 表达日后要完成的事情.

class Future:

def __init__(self):

self.result = None

self._callbacks = []

def add_done_callback(self, fn):

self._callbacks.append(fn)

def set_result(self, result):

self.result = result

for fn in self._callbacks:

fn(self)

每次执行set_result会调用call_back

Task

Task是用来驱动future的

class Task:

def __init__(self, coro):

self.coro = coro

f = Future()

f.set_result(None)

self.step(f)

def step(self, future):

try:

next_future = self.coro.send(future.result)

except StopIteration:

return

next_future.add_done_callback(self.step)

Task 要做的事情就是每次让协程接着往下走,并且在不是最后一步的时候,把下一步加到回调里

Main

def connect(self):

self.sock.setblocking(False)

try:

self.sock.connect(('127.0.0.1',30))

except BlockingIOError:

pass

f = Future()

def on_connection():

f.result(None)

selector.register(self.sock.fileno(), selectors.EVENT_WRITE, on_connection)

yield f

selector.unregister(self.sock.fileno())

self.sock.sendall(b"hello")

while True:

f = Future()

def on_read():

f.set_result(self.sock.recv(4096))

selector.register(self.sock.fileno(), selectors.EVENT_READ, on_read)

chunk = yield f

selector.unregister(self.sock.fileno())

if chunk:

self.resp += chunk

else:

break

这里可以看到 所有的回调都加上了 set_result 方法 通过set_result 来调用绑定在future的回调,主要就是Task给 绑定的下一步的回调。

这样的好处就是不用区分事件是谁触发的了 每次都按的是同步的顺序走的。

Eventloop

c = Client()

Task(c.connect())

while True:

events = selector.select()

for key, mask in events:

callback = key.data

callback()

最后写出Eventloop是一件十分自然的事情, 先把任务加到Task里预激励它。然后每次触发事件就调用set_result方法来调用Task给他 附加的step的回调,让协程一直往下走。这样就用可以让代码保持了同步的顺序又能异步执行了。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值