简介
在 python 3中,加入了 asyncio 模块,来实现协程,其中一个很重要的概念是事件循环,整个异步流程都是事件循环推动的。下面自己实现一个相对简单的EventLoop,了解一下事件循环是如何进行运转的。
事件循环
下面看一下整个流程的实现过程
将以下代码写入 spider_event_loop.py 文件:
# spider_event_loop.py
import time
import os
import socket
from urllib.parse import urlparse
from collections import deque
from selectors import DefaultSelector, EVENT_WRITE, EVENT_READ
# selector = DefaultSelector()
urls = ['https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9bc51bc53f634bf79b5de5c8b9810817~tplv-k3u1fbpfcp-watermark.image',
'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2b95ac8571ba403180743495ed56e492~tplv-k3u1fbpfcp-watermark.image',
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/459c6c73887a4206a33b13ef23988809~tplv-k3u1fbpfcp-watermark.image',
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/80701ade82d345cd8aa0b08fef008fe1~tplv-k3u1fbpfcp-watermark.image',
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99855ed1f79c456f9fdcd83ce5cff4f2~tplv-k3u1fbpfcp-watermark.image',
'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0c4bd38c2fe3434587025748d051362e~tplv-k3u1fbpfcp-watermark.image',
'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/80cd2a1d165b43beb6234d893ce391e2~tplv-k3u1fbpfcp-watermark.image',
'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ea18df95f26f4314a0a36d11d4a067d0~tplv-k3u1fbpfcp-watermark.image',
'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/095c342a796c411cad1800396746bdaf~tplv-k3u1fbpfcp-watermark.image',
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d3769e4d468a4f64a1e2879f94ad742b~tplv-k3u1fbpfcp-watermark.image'
]
# 事件循环实现
class EventLoop:
def __init__(self):
# 整个流程是否
self._stopped = False
self._ready = deque()
self._selector = DefaultSelector()
# 向 _ready 队列中加入回调方法
def call_soon(self, callback, *args):
# 将事件添加到队列里
handle = Handle(callback, self, *args)
self._ready.append(handle)
# 套接字注册读事件
def add_writer(self, fd, callback, *args):
# 将回调方法封装成Handle
handle = Handle(callback, self, *args)
try:
# 检查有没有注册过
key = self._selector.get_key(fd)
except KeyError:
# 没有注册过,进行写事件注册
self._selector.register(fd, EVENT_WRITE, handle)
else:
# 注册过,添加写事件
mask = key.events
self._selector.modify(fd, mask | EVENT_WRITE, handle)
# 套接字注销读事件
def remove_writer(self, fd):
try:
# 检查有没有注册过
self._selector.get_key(fd)
except KeyError:
# 没有,直接返回
return
# 注销事件
self._selector.unregister(fd)
# 套接字注册写事件
def add_reader(self, fd, callback, *args):
# 将回调方法,封装成Handle
handle = Handle(callback, self, *args)
try:
# 检查是否注册过
key = self._selector.get_key(fd)
except KeyError:
# 没有注册过,进行读事件注册
self._selector.register(fd, EVENT_READ, handle)
else:
# 注册过,添加读事件
mask = key.events
self._selector.modify(fd, mask | EVENT_READ, handle)
# 套接字注销写事件
def remove_reader(self, fd):
try:
# 检查有没有注册过
self._selector.get_key(fd)
except KeyError:
# 没有,直接返回
return
# 注销事件
self._selector.unregister(fd)
# 处理事件
def _process_events(self, event_list):
for key, mask in eve