首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
1.1 HTTP基本原理
1.2 Web 网页基础
1.3 爬虫的基本原理
1.4 Session和Cookie
1.5 代理的基本原理
1.6 多线程和多进程的基本原理
2.1 urllib的使用
2.2 requests的使用
2.3 正则表达式
2.4 httpx的使用
2.5 基础爬虫案例实战
3.1 XPath的使用
3.2 Beautiful Soup的使用
3.3 pyquery的使用
3.4 parsel 的使用
4.1 TXT 文本文件存储
4.2 JSON 文件存储
4.3 CSV 文件存储
4.4 MySQL 存储
4.5 MongoDB 文档存储
4.6 Redis缓存存储
4.7 Elasticsearch 搜索引擎存储
4.8 RabbitMQ 的使用
5.1 什么是 Ajax
5.2 Ajax分析方法
5.3 Ajax 分析与爬取实战
6.1 协程的基本原理
6.2 aiohttp的使用
6.3 aiohttp 异步爬取实战
7.1 Selenium 的使用
7.2 Splash 的使用
7.3 Pyppeteer 的使用
7.4 Playwright 的使用
7.5 Selenium 爬取实战
7.6 Pyppeteer 爬取实战
7.7 CSS 位置偏移反爬案例分析与爬取实战
7.8 字体反爬案例分析与爬取实战
8.1 使用 OCR 技术识别图形验证码
8.2 使用 OpenCV 识别滑动验证码的缺口
8.3 使用深度学习识别图形验证码
8.4 使用深度学习识别滑动验证码的缺口
8.5 使用打码平台识别验证码
8.6 手机验证码的自动化处理
9.1 代理的设置
9.2 代理池的维护
9.3 付费代理的使用
9.4 ADSL 拨号代理的搭建方法
9.5 代理反爬案例爬取实战
10.1 模拟登录的基本原理
10.2 基于Session和Cookie的模拟登录爬取实战
10.3 基于JWT的模拟登录爬取实战
10.4 大规模账号池的搭建
11.1 网站加密和混淆技术简介
11.2 浏览器调试常用技巧
11.3 JavaScript Hook 的使用
11.4 无限 debugger 的原理与绕过
11.5 使用 Python 模拟执行 JavaScript
11.6 使用 Node.js 模拟执行 JavaScript
11.7 浏览器环境下 JavaScript 的模拟执行
11.8 AST 技术简介
11.9 使用 AST 技术还原混淆代码
11.10 特殊混淆案例的还原
11.11 WebAssembly 案例分析和爬取实战
11.12 JavaScript 逆向技巧总结
11.13 JavaScript 逆向爬取实战
当前位置:
首页>>
技术小册>>
Python3网络爬虫开发实战(上)
小册名称:Python3网络爬虫开发实战(上)
### 1.6 多线程和多进程的基本原理 在Python网络爬虫的开发过程中,处理大规模数据、提高程序执行效率是常见的需求。为了充分利用计算机的多核CPU资源,减少等待时间,多线程(Multi-threading)和多进程(Multi-processing)技术成为了不可或缺的工具。本章将深入探讨多线程与多进程的基本原理,包括它们的定义、区别、适用场景以及在Python中的实现方式。 #### 1.6.1 引言 在理解多线程和多进程之前,我们需要先明确“进程”与“线程”这两个基本概念。进程是系统进行资源分配和调度的一个独立单元,是操作系统结构的基础。它拥有独立的内存空间和系统资源。而线程则是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的独立运行的单位。一个进程可以拥有多个线程,这些线程共享进程的资源(如内存、文件句柄等)。 #### 1.6.2 多线程的基本原理 ##### 1.6.2.1 线程的概念 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。每个线程都有自己独立的程序计数器、寄存器集合和堆栈,但共享进程所拥有的内存和其他资源。因此,线程之间的切换开销比进程小得多,这使得多线程程序能够更高效地利用CPU资源。 ##### 1.6.2.2 多线程的优势与局限 - **优势**: - **提高程序执行效率**:通过并行执行多个任务,减少等待时间。 - **资源共享**:线程间共享进程的资源,减少内存消耗。 - **简化通信**:线程间通信通常比进程间通信简单快捷。 - **局限**: - **资源竞争与同步问题**:多个线程可能同时访问同一资源,导致数据不一致或死锁。 - **线程创建与销毁开销**:虽然比进程小,但大量线程的创建与销毁也会带来性能损耗。 - **GIL(全局解释器锁)**:在Python中,由于GIL的存在,限制了多线程在执行CPU密集型任务时的并行性,但在I/O密集型任务中仍能有效提升性能。 ##### 1.6.2.3 Python中的多线程实现 Python标准库中的`threading`模块提供了多线程编程的支持。通过创建`Thread`类的实例并调用其`start()`方法,可以启动一个新的线程。Python中使用锁(如`Lock`、`RLock`)、条件变量(`Condition`)、信号量(`Semaphore`)等机制来解决线程间的同步问题。 ```python import threading def worker(): """线程工作函数""" print(f"Thread {threading.current_thread().name} is running") # 创建线程 t1 = threading.Thread(target=worker, name='Thread-1') t2 = threading.Thread(target=worker, name='Thread-2') # 启动线程 t1.start() t2.start() # 等待所有线程完成 t1.join() t2.join() ``` #### 1.6.3 多进程的基本原理 ##### 1.6.3.1 进程的概念 进程是系统进行资源分配和调度的一个独立单元,它拥有独立的内存空间、文件描述符等资源。每个进程都有自己的虚拟地址空间,进程间的通信(IPC)需要通过特定的机制来实现,如管道、消息队列、共享内存等。 ##### 1.6.3.2 多进程的优势与局限 - **优势**: - **真正的并行执行**:在多核CPU上,多进程可以真正并行执行,提高CPU利用率。 - **资源隔离**:进程间资源独立,避免了资源竞争和数据不一致的问题。 - **稳定性**:一个进程的崩溃不会影响其他进程。 - **局限**: - **通信复杂**:进程间通信(IPC)相比线程间通信更为复杂和开销大。 - **资源消耗**:每个进程都需要独立的内存空间等资源,系统资源消耗较大。 ##### 1.6.3.3 Python中的多进程实现 Python的`multiprocessing`模块提供了对多进程编程的全面支持。该模块通过封装底层的进程创建和管理功能,使得Python程序能够利用多核CPU的优势。`multiprocessing`模块中的`Process`类与`threading`模块中的`Thread`类用法类似,但用于创建进程。 ```python from multiprocessing import Process def worker(): """进程工作函数""" print(f"Process {Process.current_process().name} is running") # 创建进程 p1 = Process(target=worker, name='Process-1') p2 = Process(target=worker, name='Process-2') # 启动进程 p1.start() p2.start() # 等待所有进程完成 p1.join() p2.join() ``` #### 1.6.4 多线程与多进程的比较与选择 - **CPU密集型任务**:对于CPU密集型任务,由于GIL的存在,Python中的多线程无法充分利用多核CPU的优势。此时,推荐使用多进程。 - **I/O密集型任务**:对于I/O密集型任务,如网络爬虫中的网页下载、数据库操作等,多线程可以有效减少等待时间,提高程序的执行效率。 - **内存与资源消耗**:多进程相比多线程会消耗更多的系统资源,因为每个进程都需要独立的内存空间。 - **数据共享与同步**:多线程在数据共享和同步方面相对简单,但容易引发数据竞争和死锁问题;多进程则通过IPC机制进行通信,复杂度较高但可以避免数据竞争问题。 #### 1.6.5 高级话题:线程池与进程池 在实际开发中,频繁地创建和销毁线程或进程会带来较大的性能开销。为了优化性能,可以使用线程池(ThreadPool)或进程池(ProcessPool)来管理一组固定的线程或进程,通过复用这些线程或进程来执行多个任务。Python的`concurrent.futures`模块提供了`ThreadPoolExecutor`和`ProcessPoolExecutor`类,分别用于创建线程池和进程池。 ```python from concurrent.futures import ThreadPoolExecutor, as_completed def worker(n): """线程工作函数""" return f"Result of {n*n}" # 使用线程池 with ThreadPoolExecutor(max_workers=5) as executor: future_to_url = {executor.submit(worker, n): n for n in range(5)} for future in as_completed(future_to_url): url = future_to_url[future] try: data = future.result() except Exception as exc: print(f'{url} generated an exception: {exc}') else: print(f'{url} returned {data}') ``` #### 1.6.6 结论 多线程和多进程是提高程序执行效率、充分利用计算机资源的重要手段。在Python网络爬虫开发中,根据任务类型(CPU密集型或I/O密集型)和资源消耗情况,合理选择多线程或多进程,以及使用线程池或进程池来优化性能,是提升爬虫效率的关键。通过深入理解多线程和多进程的基本原理及其在Python中的实现方式,开发者可以更加灵活地设计高效、稳定的网络爬虫系统。
上一篇:
1.5 代理的基本原理
下一篇:
2.1 urllib的使用
该分类下的相关小册推荐:
Python高并发编程与实战
Python3网络爬虫开发实战(下)
实战Python网络爬虫
Python面试指南
剑指Python(万变不离其宗)
Python高性能编程与实战
Python合辑8-变量和运算符
Python神经网络入门与实践
Python合辑3-字符串用法深度总结
Python机器学习基础教程(上)
Python与办公-玩转PDF
Python数据分析与挖掘实战(下)