MST
星途 面试题库

面试题:网络编程中Python gevent库协程基础应用

请简述gevent库中协程的概念,以及如何使用gevent创建简单的协程来实现多个网络请求的并发处理,例如获取多个网页的内容。请给出核心代码示例并解释原理。
40.0万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

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. 原理解释

  1. monkey.patch_all():这行代码是gevent库的关键,它会将标准库中一些阻塞式的IO操作替换为gevent中可协作式切换的版本。例如,将requests.get操作变为非阻塞的,当遇到网络等待时,协程可以切换去执行其他任务。
  2. 定义fetch函数:该函数接收一个URL作为参数,使用requests.get发起网络请求并获取网页内容。在请求过程中,如果使用了monkey.patch_all(),当遇到网络IO等待时,gevent会自动切换到其他就绪的协程。
  3. 创建协程任务:通过列表推导式[pool.spawn(fetch, url) for url in urls]为每个URL创建一个协程任务,pool.spawn方法会将任务提交到协程池pool中。
  4. 等待所有协程完成gevent.joinall(jobs)语句会阻塞当前线程,直到所有协程任务执行完毕。
  5. 获取结果:通过[job.value for job in jobs if job.value is not None]获取每个协程任务的返回值,即获取到的网页内容。如果某个协程执行过程中发生错误,其返回值为None,会被过滤掉。