当前位置: 首页 > news >正文

Python并发与异步编程

Python的并发与异步编程是两个不同的概念,但它们经常一起使用,以提高程序的性能和响应能力。以下是对这两个概念的详细讲解:

并发编程 (Concurrency)
并发编程是指在程序中同时执行多个任务的能力。Python提供了几种实现并发的机制:

1. 多线程 (Threading):
   - Python的`threading`模块允许你创建线程,从而在同一时间内执行多个操作。
   - 由于Python的全局解释器锁(GIL),真正的并行执行在多线程中受到限制,这意味着在任何给定时间点,只有一个线程可以执行Python字节码。
   - 多线程适合I/O密集型任务,例如网络请求或文件操作。

2. 多进程 (Multiprocessing):
   - `multiprocessing`模块提供了创建多个进程的方法,每个进程有自己的Python解释器和内存空间。
   - 由于进程之间没有GIL的限制,因此它们可以实现真正的并行执行。
   - 多进程适合CPU密集型任务,但进程间通信和创建进程的开销较大。

3. 协程 (Coroutines):
   - 协程是一种更轻量级的并发机制,通过`asyncio`库实现。
   - 协程允许你编写看似同步的代码,而实际上是异步执行的,这使得I/O操作更加高效。

异步编程 (Asynchronous Programming)
异步编程是一种编程范式,允许程序在等待操作完成时继续执行其他任务。Python中的异步编程主要通过`asyncio`库实现:

1. asyncio:
   - `asyncio`是一个用于编写单线程并发代码的库,使用`async`和`await`关键字。
   - `async def`用于定义一个异步函数,它可以包含`await`表达式。
   - `await`用于等待另一个异步操作完成,同时允许其他异步操作运行。
   - `asyncio`提供了事件循环(event loop),它是运行异步任务的核心。2. 使用asyncio的例子:
   ```python
   

import asyncioasync def fetch_data():# 模拟I/O操作await asyncio.sleep(2)return {"data": 1}async def main():# 获取事件循环引用data = await fetch_data()print(data)asyncio.run(main())


   ```

3. 异步I/O:
   - 除了`asyncio`,Python还提供了用于异步I/O操作的库,如`aiohttp`用于异步HTTP请求。

并发与异步的结合
在Python中,可以结合使用并发和异步编程来最大化性能。例如,可以使用`asyncio`进行异步编程,同时利用`multiprocessing`来实现CPU密集型任务的并行处理。

注意事项
- 并发编程可能会引入竞态条件和死锁,需要仔细设计。
- 异步编程的代码可能难以理解和调试,特别是对于初学者。
- 选择哪种并发或异步模型取决于具体的应用场景和性能要求。

多线程在爬虫程序中的应用可以显著提高数据抓取的效率。以下是一个使用Python的`threading`模块实现的简单多线程爬虫案例的详细讲解:

 1. 准备工作
在开始编写多线程爬虫之前,需要准备以下内容:
目标网站**:确定要爬取的网站和数据。
请求库**:如`requests`,用于发送网络请求。
解析库**:如`BeautifulSoup`,用于解析HTML页面。
线程模块**:`threading`,用于创建和管理线程。

 2. 安装必要的库
如果尚未安装`requests`和`BeautifulSoup`,可以通过以下命令安装:
```bash

pip install requests beautifulsoup4


```

 3. 编写爬虫函数
编写一个基本的爬虫函数,用于请求网页并解析数据。```python

import requests
from bs4 import BeautifulSoupdef crawl(url):try:response = requests.get(url)response.raise_for_status()  # 检查请求是否成功soup = BeautifulSoup(response.text, 'html.parser')# 假设我们爬取的是网页标题title = soup.find('title').get_text()print(f"页面标题: {title}")except requests.RequestException as e:print(f"请求错误: {e}")except Exception as e:print(f"解析错误: {e}")


```

 4. 创建线程工作函数
编写一个线程工作函数,它将作为线程执行的主体。

```python

def worker(url):crawl(url)


```

 5. 管理线程
创建一个函数来管理线程的创建和启动。```python

def manage_threads(urls):threads = []for url in urls:thread = threading.Thread(target=worker, args=(url,))threads.append(thread)thread.start()# 等待所有线程完成for thread in threads:thread.join()# 爬取的URL列表
urls = ['http://example.com','http://example.org','http://example.net',# 添加更多URL...
]


```

 6. 运行爬虫
调用`manage_threads`函数并传入URL列表。

```python

if __name__ == "__main__":manage_threads(urls)


```

 7. 注意事项
GIL限制**:由于Python的GIL,多线程在执行CPU密集型任务时可能不会带来太大的性能提升。但对于I/O密集型任务,如网络请求,多线程可以显著提高效率。
线程安全**:在多线程环境下,共享数据时需要注意线程安全问题,避免竞态条件。
资源限制**:过多的线程可能会导致资源竞争和调度问题,需要合理控制线程数量。
异常处理**:每个线程都应该能够妥善处理异常,避免线程崩溃导致整个程序异常。

 8. 扩展功能
限制速率**:可以引入时间延迟来遵守网站的爬虫政策。
用户代理**:设置用户代理(User-Agent)来模拟浏览器请求。
Cookies处理**:处理Cookies以维持会话状态。
重试机制**:对失败的请求实施重试策略。

这个案例展示了多线程爬虫的基本结构和实现方法。在实际应用中,你可能需要根据目标网站的特点和反爬措施进行相应的调整和优化。

让我们继续扩展上面的例子,创建一个更完整的多线程爬虫案例。这个案例将包括以下功能:

1. 多线程爬取网页
2. 解析网页内容
3. 限制请求速率
4. 简单的错误处理和日志记录

首先,我们需要安装所需的库(如果尚未安装):

```bash

pip install requests beautifulsoup4


```

然后,我们将创建一个更完整的多线程爬虫程序:```python

import requests
from bs4 import BeautifulSoup
import threading
import time
import logging
from queue import Queue# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# 请求队列
url_queue = Queue()
# 存放结果的队列
result_queue = Queue()def crawl(url):try:response = requests.get(url, timeout=5)response.raise_for_status()  # 检查请求是否成功soup = BeautifulSoup(response.text, 'html.parser')# 假设我们爬取的是网页的标题和一些链接title = soup.find('title').get_text()links = [a['href'] for a in soup.find_all('a', href=True)]result_queue.put((url, title, links))logging.info(f"成功爬取: {url}")except requests.RequestException as e:logging.error(f"请求错误: {url} - {e}")except Exception as e:logging.error(f"解析错误: {url} - {e}")def worker():while not url_queue.empty():url = url_queue.get()crawl(url)# 模拟网络延迟time.sleep(1)def manage_threads(url_list, thread_count=5):# 将URL加入队列for url in url_list:url_queue.put(url)# 创建并启动线程threads = []for _ in range(thread_count):thread = threading.Thread(target=worker)threads.append(thread)thread.start()# 等待所有线程完成for thread in threads:thread.join()# 打印结果while not result_queue.empty():url, title, links = result_queue.get()print(f"URL: {url}, Title: {title}, Links: {links}")# 爬取的URL列表
urls = ['http://example.com','http://example.org','http://example.net',# 添加更多URL...
]if __name__ == "__main__":manage_threads(urls, thread_count=10)


```

### 案例详解:

- 日志记录:使用`logging`模块记录日志,方便跟踪爬虫的状态和错误。
- 请求队列:使用`Queue`来管理URL列表,线程安全地在多个线程间传递任务。
- 结果队列:同样使用`Queue`来存放爬取的结果。
- 速率限制:通过`time.sleep(1)`模拟网络延迟,限制请求速率,避免对目标网站造成过大压力。
- 线程管理:`manage_threads`函数负责初始化队列、启动线程和收集结果。

### 注意事项:

- 线程数量:创建的线程数量应根据目标网站和服务器性能进行调整。
- 异常处理:每个线程都应该能够处理请求和解析过程中可能出现的异常。
- 队列处理:确保队列在所有线程中正确地被管理,避免竞态条件。
- 资源管理:确保所有网络请求和线程都正确地被管理,避免资源泄露。

这个案例提供了一个基本的多线程爬虫框架,可以根据具体需求进行扩展和优化。

相关文章:

Python并发与异步编程

Python的并发与异步编程是两个不同的概念,但它们经常一起使用,以提高程序的性能和响应能力。以下是对这两个概念的详细讲解: 并发编程 (Concurrency) 并发编程是指在程序中同时执行多个任务的能力。Python提供了几种实现并发的机制&#xff…...

动态内存管理—C语言通讯录

目录 一,动态内存函数的介绍 1.1 malloc和free 1.2 calloc 1.3 realloc 1.4C/C程序的内存开辟 二,通讯录管理系统 动态内存函数的介绍 malloc free calloc realloc 一,动态内存函数的介绍 1.1 malloc和free void* malloc (…...

美光EMMC芯片丝印型号查询 8LK17/D9PSK, OXA17/JY997

问题说明 最近在使用美光EMMC的时候,发现通过芯片丝印查询不到 芯片的规格说明书; 经过查阅资料,发现美光的EMMC芯片 “由于空间限制,FBGA 封装组件具有与部件号不同的缩写部件标记”,需要通过官网查询丝印的FBGA cod…...

win32-鼠标消息、键盘消息、计时器消息、菜单资源

承接前文: win32窗口编程windows 开发基础win32-注册窗口类、创建窗口win32-显示窗口、消息循环、消息队列 本文目录 键盘消息键盘消息的分类WM_CHAR 字符消息 鼠标消息鼠标消息附带信息 定时器消息 WM_TIMER创建销毁定时器 菜单资源资源相关菜单资源使用命令消息的…...

springboot项目部署到linux服务器

springboot后端 修改前 修改后 vue前端 修改前 将地址中的 localhost改为 ip 重新生成war包 war上传到linux的tomcat的webapps下 其他环境配置和macOS大差不差 Tomcat安装使用与部署Web项目的三种方法_tomcat部署web项目-CSDN博客...

MagicLens:新一代图像搜索技术和产品形态

MagicLens:Self-Supervised Image Retrieval with Open-Ended Instructions MagicLens: 自监督图像检索与开放式指令 作者:Kai Zhang, Yi Luan, Hexiang Hu, Kenton Lee, Siyuan Qiao, Wenhu …...

[9] CUDA性能测量与错误处理

CUDA性能测量与错误处理 讨论如何通过CUDA事件来测量它的性能如何通过CUDA代码进行调试 1.测量CUDA程序的性能 1.1 CUDA事件 CPU端的计时器可能无法给出正确的内核执行时间CUDA事件等于是在你的CUDA应用运行的特定时刻被记录的时间戳,通过使用CUDA事件API&#…...

Java学习四

Random 随机数 数组 静态初始化数组 数组在计算机中的基本原理 数组的访问 什么是遍历 数组的动态初始化 动态初始化数组元素默认值规则 Java内存分配介绍 数组在计算机中的执行原理 使用数组时常见的一个问题 案例求数组元素最大值 public class Test1 {public static void ma…...

Vue 父组件使用refs来直接访问和修改子组件的属性或调用子组件的方法

步骤 1: 在子组件中定义要被修改的属性或方法 首先,在子组件中定义你想要父组件能够修改或调用的属性或方法。例如,我们有一个名为MyChildComponent的子组件,它有一个名为childData的数据属性和一个名为updateData的方法。 // 子组件 MyChi…...

范罗士、希喂、安德迈爆款宠物空气净化器哪款好?深度对比测评

作为一名深受养猫过敏困扰的铲屎官,我经常提醒新手铲屎官重视家里的空气环境。宠物的浮毛和皮屑不仅会引发过敏,还可能传播细菌和病毒。很多人以为普通空气净化器能解决问题,但这些产品并未针对宠物家庭的特殊需求。经过多次研究和测试&#…...

SAP OBYC自动记账 详解

在MM模块的许多操作都能实现在FI模块自动过账,如PO收货、发票验证、工单发料、向生产车间发料等等。不用说,一定需要在IMG中进行配置才可以实现自动处理。但SAP实现的这种自动配置的机制是怎样的呢?其实也并不复杂,让我们先以一种最简单的情况来了解实现原理和实现流程,然…...

《NoSQL数据库技术与应用》 MongoDB副本集

《NoSQL数据库技术与应用》 教学设计 课程名称:NoSQL数据库技术与应用 授课年级: 20xx年级 授课学期: 20xx学年第一学期 教师姓名: 某某老师 2020年5月6日 课题 名称 第4章 MongoDB副本集 计划学时 8课时 内容 分析 独立模式可…...

Flutter 中的 DropdownButtonFormField 小部件:全面指南

Flutter 中的 DropdownButtonFormField 小部件:全面指南 在Flutter中,DropdownButtonFormField是一个特殊的表单字段小部件,它结合了下拉选择框(DropdownButton)和表单字段(FormField)的功能。…...

哈希算法教程(个人总结版)

背景 哈希算法(Hash Algorithm)是一种将任意长度的输入(也称为消息)转换为固定长度的输出(也称为哈希值、散列值、摘要)的算法。哈希算法在计算机科学中有着广泛的应用,包括数据存储、数据检索…...

Nocobase快速上手 -第一个collection

本文记录Nocobase中如何创建collection,以及如何将collection展示到页面中,并且配置CRUD相应的操作. Collection 在NocoBase中,collection(集合)是用来组织和存储各种数据的容器,如订单、产品、用户、评论…...

吴恩达2022机器学习专项课程C2W2:2.19 sigmoid函数的替代方案 2.20如何选择激活函数 2.21 激活函数的重要性

这里写目录标题 引言sigmoid激活函数的局限1.回顾需求案例2.ReLU激活函数 常用的激活函数1.线性激活函数的解释 如何选择激活函数?1.选择输出层的激活函数2.选择隐藏层的激活函数 选择激活函数的总结1.输出层总结2.隐藏层总结3.TensorFlow设置激活函数 激活函数多样…...

循序渐进Docker Compose

文章目录 1.概述1.1 Docker Compose 定义1.2 Docker Compose背景1.3 Docker Compose核心概念 2.安装2.1 Official Repos2.2 Manual Installation2.3 v1.x 兼容性 3. YAML 配置说明3.1 Services3.2 Volumes & Networks 4. 解析 Service4.1 Pulling一个Image4.2 Building一个…...

怎样查看JavaScript中没有输出结果的数组值?

在JavaScript中,可以方便地定义和使用数组,对于已经定义的数组,怎样查看其值呢? 看下面的示例,并运行它。 上面的示例中,标签不完整,请补充完整再试运行。你知道少了什么标签么? 注…...

强化学习学习笔记-李宏毅

Policy Gradient actorenvreward function,env和reward是不能控制的,唯一可以变的是actor,Policy π \pi π是一个网络,参数为 θ \theta θ,输入是当前的观察,输出是采取的行为,例如游戏中输…...

吴恩达深度学习笔记:超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架(Hyperparameter tuning)3.8-3.9

目录 第二门课: 改善深层神经网络:超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第三周: 超 参 数 调 试 、 Batch 正 则 化 和 程 序 框 架(Hyperparameter …...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...