面试题答案
一键面试1. gevent库中协程的概念
协程,又称微线程,纤程。在Python中,协程是一种用户态的轻量级线程。gevent库中的协程基于greenlet实现,它允许程序在执行到IO操作(如网络请求、文件读写等)时,自动切换到其他协程执行,从而实现高效的并发处理。这种切换是协作式的,而非抢占式的,避免了线程切换带来的上下文切换开销和锁竞争问题。
2. 使用gevent创建简单协程实现多个网络请求并发处理的核心代码示例
import gevent
from gevent import monkey
from gevent.pool import Pool
import requests
# 打补丁,让gevent识别标准库中的IO操作
monkey.patch_all()
def fetch(url):
try:
response = requests.get(url)
print(f"Successfully fetched {url}, status code: {response.status_code}")
return response.text
except Exception as e:
print(f"Error fetching {url}: {e}")
return None
urls = [
'http://www.example.com',
'http://www.google.com',
'http://www.github.com'
]
pool = Pool(5) # 创建一个协程池,最大并发数为5
jobs = [pool.spawn(fetch, url) for url in urls]
gevent.joinall(jobs)
results = [job.value for job in jobs if job.value is not None]
3. 原理解释
- monkey.patch_all():这行代码是gevent库的关键,它会将标准库中一些阻塞式的IO操作替换为gevent中可协作式切换的版本。例如,将
requests.get
操作变为非阻塞的,当遇到网络等待时,协程可以切换去执行其他任务。 - 定义fetch函数:该函数接收一个URL作为参数,使用
requests.get
发起网络请求并获取网页内容。在请求过程中,如果使用了monkey.patch_all()
,当遇到网络IO等待时,gevent会自动切换到其他就绪的协程。 - 创建协程任务:通过列表推导式
[pool.spawn(fetch, url) for url in urls]
为每个URL创建一个协程任务,pool.spawn
方法会将任务提交到协程池pool
中。 - 等待所有协程完成:
gevent.joinall(jobs)
语句会阻塞当前线程,直到所有协程任务执行完毕。 - 获取结果:通过
[job.value for job in jobs if job.value is not None]
获取每个协程任务的返回值,即获取到的网页内容。如果某个协程执行过程中发生错误,其返回值为None
,会被过滤掉。