在进行多个内容一起进行抓取时,多线程/异步抓取如何实现
通常使用concurrent.futures 和 aiohttp
concurrent.futures
Python 标准库中的一个模块,用于实现异步编程,它提供了一个高级接口来处理异步执行的可调用对象(如函数)
优势在于:使用线程池自动管理线程的生命周期,提供简洁的接口提交任务和获取结果,支持超时和错误处理,代码更加 Pythonic 和易于维护
这个模块有两个池执行器:ThreadPoolExecutor 和 ProcessPoolExecutor
ThreadPoolExecutor :用于异步执行线程
ProcessPoolExecutor:用于异步执行进程
ThreadPoolExecutor | ProcessPoolExecutor |
---|---|
线程池:ThreadPoolExecutor 使用线程来执行任务。线程是轻量级的,创建和销毁的开销较小,且切换速度快。 | 进程池:ProcessPoolExecutor 使用进程来执行任务。进程是重量级的,创建和销毁的开销较大,且切换速度慢,但每个进程有自己的内存空间和 Python 解释器。 |
GIL的影响:由于 Python 的全局解释器锁(GIL),即使在多线程环境中,同一时刻也只有一个线程可以执行 Python 字节码。这意味着在 CPU 密集型任务中,多线程可能不会带来性能上的提升,因为线程会被 GIL 限制。 | GIL无影响:由于每个进程有自己的 Python 解释器,因此它们不受 GIL 的限制。这意味着在 CPU 密集型任务中,多进程可以真正地并行执行,从而提高性能。 |
适用场景:适用于 I/O 密集型任务,例如文件读写、网络请求等,这些任务会花费大量时间等待 I/O 操作完成,从而释放 GIL,让其他线程有机会执行。 | 适用场景:适用于 CPU 密集型任务,例如复杂的计算、数据处理等,这些任务可以通过多进程实现真正的并行计算。 |
如果你的任务主要是 I/O 密集型的,那么 ThreadPoolExecutor 可能是更好的选择,因为它可以更高效地利用多核 CPU 处理 I/O 操作。
如果你的任务主要是 CPU 密集型的,那么 ProcessPoolExecutor 可能是更好的选择,因为它可以绕过 GIL 的限制,实现真正的并行计算。
在使用 ProcessPoolExecutor 时,需要注意进程间通信(IPC)的开销,以及进程创建和销毁的开销。
在使用 ThreadPoolExecutor 时,需要注意 GIL 对多线程执行的影响,以及线程安全问题。
aiohttp
基于Python的asyncio框架的 HTTP 客户端和服务器异步库,利用 asyncio 的事件循环机制,可以轻松地集成到异步应用中
优势在于性能,比传统的基于线程的库(如 requests 和 Flask )更适合高并发的场景