【Python】教你彻底了解Python中的并发编程

​​​​在这里插入图片描述

文章目录

    • 一、并发编程的基本概念
      • 1. 线程(Thread)
      • 2. 进程(Process)
      • 3. 协程(Coroutine)
    • 二、Python中的线程与进程
      • 1. 线程
        • 1.1 创建和启动线程
        • 1.2 线程同步
      • 2. 多进程
        • 2.1 创建和启动进程
        • 2.2 进程间通信
    • 三、异步编程
      • 1. 协程
        • 1.1 定义和调用协程
      • 2. 异步任务
    • 四、并发编程的实际应用示例
      • 1. 多线程Web爬虫
      • 2. 多进程图像处理
    • 五、并发编程的注意事项
      • 1. 线程安全
      • 2. 死锁
      • 3. 资源消耗
      • 4. 异常处理
    • 结论

随着计算机处理能力的不断提升和多核处理器的普及,并发编程变得越来越重要。并发编程可以使程序同时执行多个任务,从而提高程序的性能和响应速度。在Python中,有多种方式可以实现并发编程,包括线程、进程和异步编程。在这篇文章中,我们将深入探讨Python中的并发编程,涵盖其基本概念、线程与进程、多线程编程、多进程编程、异步编程以及并发编程的实际应用示例。

一、并发编程的基本概念

并发编程是指同时执行多个任务的编程技术。并发编程的目标是提高程序的执行效率和响应速度。在并发编程中,有几个重要的概念需要理解:

1. 线程(Thread)

线程是程序执行的最小单位。一个进程可以包含多个线程,每个线程可以执行不同的任务。线程之间可以共享内存,因此线程之间的通信比较容易,但需要注意线程安全问题。

2. 进程(Process)

进程是程序执行的一个实例。每个进程有自己独立的内存空间,相互之间不会影响。多进程编程可以有效利用多核处理器,但进程之间的通信相对复杂。

3. 协程(Coroutine)

协程是一种比线程更轻量级的并发实现方式。协程在执行过程中可以暂停和恢复,从而实现非阻塞的并发执行。Python中的异步编程通常使用协程来实现。

二、Python中的线程与进程

Python中提供了多种实现并发编程的方式,包括线程、多进程和异步编程。我们将分别介绍这些方法,并讨论它们的优缺点。

1. 线程

Python中的threading模块提供了创建和管理线程的功能。通过threading.Thread类,我们可以创建和启动线程。

1.1 创建和启动线程

以下示例展示了如何创建和启动线程:

import threadingdef print_numbers():for i in range(1, 6):print(i)# 创建线程
thread = threading.Thread(target=print_numbers)# 启动线程
thread.start()# 等待线程结束
thread.join()
print("Thread execution completed.")

在上面的例子中,我们创建了一个线程来执行print_numbers函数,并启动了线程。join方法用于等待线程执行完成。

1.2 线程同步

在多线程编程中,多个线程可能会同时访问共享资源,从而导致数据不一致的问题。为了避免这种情况,我们可以使用线程同步机制,如锁(Lock)。

以下示例展示了如何使用锁来同步线程:

import threadingcounter = 0
lock = threading.Lock()def increment_counter():global counterfor _ in range(1000000):with lock:counter += 1# 创建和启动线程
threads = []
for _ in range(5):thread = threading.Thread(target=increment_counter)threads.append(thread)thread.start()# 等待所有线程结束
for thread in threads:thread.join()print(f"Final counter value: {counter}")

在上面的例子中,我们使用锁来确保每次只有一个线程可以访问和修改counter变量,从而避免数据不一致的问题。

2. 多进程

Python中的multiprocessing模块提供了创建和管理进程的功能。多进程编程可以有效利用多核处理器,提高程序的执行效率。

2.1 创建和启动进程

以下示例展示了如何创建和启动进程:

import multiprocessingdef print_numbers():for i in range(1, 6):print(i)# 创建进程
process = multiprocessing.Process(target=print_numbers)# 启动进程
process.start()# 等待进程结束
process.join()
print("Process execution completed.")

在上面的例子中,我们创建了一个进程来执行print_numbers函数,并启动了进程。join方法用于等待进程执行完成。

2.2 进程间通信

进程之间有独立的内存空间,因此进程间通信相对复杂。Python的multiprocessing模块提供了多种进程间通信的机制,如队列(Queue)和管道(Pipe)。

以下示例展示了如何使用队列进行进程间通信:

import multiprocessingdef producer(queue):for i in range(5):queue.put(i)print(f"Produced: {i}")def consumer(queue):while True:item = queue.get()if item is None:breakprint(f"Consumed: {item}")# 创建队列
queue = multiprocessing.Queue()# 创建和启动生产者和消费者进程
producer_process = multiprocessing.Process(target=producer, args=(queue,))
consumer_process = multiprocessing.Process(target=consumer, args=(queue,))producer_process.start()
consumer_process.start()# 等待生产者进程结束
producer_process.join()# 发送终止信号给消费者进程
queue.put(None)# 等待消费者进程结束
consumer_process.join()
print("Producer and Consumer execution completed.")

在上面的例子中,我们使用队列来在生产者和消费者进程之间传递数据。

三、异步编程

异步编程是一种高效的并发编程方式,尤其适用于I/O密集型任务。Python中的asyncio模块提供了异步编程的支持,可以使用协程实现非阻塞的并发执行。

1. 协程

协程是一种可以在执行过程中暂停和恢复的函数。协程使用async def关键字定义,使用await关键字调用。

1.1 定义和调用协程

以下示例展示了如何定义和调用协程:

import asyncioasync def print_numbers():for i in range(1, 6):print(i)await asyncio.sleep(1)# 获取事件循环
loop = asyncio.get_event_loop()# 运行协程
loop.run_until_complete(print_numbers())
loop.close()
print("Coroutine execution completed.")

在上面的例子中,我们定义了一个协程print_numbers,并在事件循环中运行它。await asyncio.sleep(1)用于模拟异步操作。

2. 异步任务

在异步编程中,我们可以使用asyncio.create_task创建异步任务,并使用await等待任务完成。

以下示例展示了如何创建和管理异步任务:

import asyncioasync def print_numbers():for i in range(1, 6):print(i)await asyncio.sleep(1)async def main():# 创建异步任务task1 = asyncio.create_task(print_numbers())task2 = asyncio.create_task(print_numbers())# 等待所有任务完成await asyncio.gather(task1, task2)# 获取事件循环并运行主协程
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
print("All tasks completed.")

在上面的例子中,我们创建了两个异步任务,并使用asyncio.gather等待它们全部完成。

四、并发编程的实际应用示例

并发编程在实际应用中有广泛的应用,以下是两个实际应用示例,演示如何使用Python进行并发编程。

1. 多线程Web爬虫

以下示例演示如何使用多线程实现一个简单的Web爬虫:

import threading
import requests
from bs4 import BeautifulSoupurls = ['https://www.example.com/page1','https://www.example.com/page2','https://www.example.com/page3'
]def fetch_url(url):response = requests.get(url)soup = BeautifulSoup(response.text, 'html.parser')title = soup.title.stringprint(f"Title of {url}: {title}")# 创建和启动线程
threads = []
for url in urls:thread = threading.Thread(target=fetch_url, args=(url,))threads.append(thread)thread.start()# 等待所有线程结束
for thread in threads:thread.join()print("All URLs fetched.")

在上面的例子中,我们使用多线程来并发获取多个网页的标题,从而提高爬取效率。

2. 多进程图像处理

以下示例演示如何使用多进程实现并行图像处理:

import multiprocessing
from PIL import Image, ImageFilterimage_paths = ['image1.jpg','image2.jpg','image3.jpg'
]def process_image(image_path):image = Image.open(image_path)image = image.filter(ImageFilter.GaussianBlur(5))output_path = f"processed_{image_path}"image.save(output_path)print(f"Processed {image_path} and saved as {output_path}")# 创建和启动进程
processes = []
for image_path in image_paths:process = multiprocessing.Process(target=process_image, args=(image_path,))processes.append(process)process.start()# 等待所有进程结束
for process in processes:process.join()print("All images processed.")

在上面的例子中,我们使用多进程来并行处理多个图像,从而提高图像处理的效率。

五、并发编程的注意事项

并发编程可以显著提高程序的性能,但同时也带来了一些挑战和问题。以下是一些并发编程的注意事项:

1. 线程安全

在多线程编程中,多个线程可能会同时访问共享资源,从而导致数据不一致的问题。为了避免这种情况,我们需要使用线程同步机制,如锁(Lock)、信号量(Semaphore)等。

2. 死锁

死锁是指两个或多个线程互相等待对方释放资源,从而导致程序无法继续执行的情况。为了避免死锁,我们需要小心设计线程同步机制,避免循环等待的情况。

3. 资源消耗

线程和进程的创建和管理会消耗系统资源。在实际应用中,我们需要合理控制线程和进程的数量,避免资源浪费。

4. 异常处理

在并发编程中,异常处理尤为重要。我们需要捕获和处理并发任务中的异常,确保程序的稳定性和可靠性。

结论

并发编程是现代编程中的一个重要技术,可以显著提高程序的性能和响应速度。在Python中,有多种方式可以实现并发编程,包括线程、多进程和异步编程。通过理解和掌握这些技术,我们可以编写出更加高效和可靠的程序。在本文中,我们详细讨论了并发编程的基本概念、Python中的线程与进程、多线程编程、多进程编程、异步编程以及并发编程的实际应用示例。希望这篇文章能帮助你更好地理解和应用Python中的并发编程技术,从而在实际项目中获得更多的性能提升和优化效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/23467.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python神器怎么得:揭秘高效编程的四大法宝

Python神器怎么得:揭秘高效编程的四大法宝 在编程的世界里,Python以其简洁、易读和强大的功能库赢得了众多开发者的青睐。然而,想要在Python编程中达到事半功倍的效果,掌握一些神器级的工具和技巧是必不可少的。本文将从四个方面…

【Python数据预处理系列】掌握数据清洗技巧:如何高效使用drop()函数去除不需要的列

目录 一、准备数据 二、使用drop函数去除掉指定列 在数据分析和预处理的过程中,经常会遇到需要从数据集中移除某些列的情况。本文将引导您了解如何使用drop函数高效地去除不需要的列,帮助您提升数据处理技能,确保您的数据集只包含对分析有价…

MYSQL ORDER BY

在MySQL中,默认情况下,升序排序会将NULL值放在前面,因为在排序过程中,NULL会被视为最小值。然而,有时会要求在升序排序中需要将NULL值放在最后。 例如根据日期升序时就会出现这种问题 方案一: SELECT sor…

【PostgreSQL 小课】日志及审计 01:日志

日志及审计 01:日志 以下内容是来自于我的知识星球:《PostgreSQL 小课》专栏,有需要可以关注一下 PostgreSQL 提供了非常丰富的日志基础设施。能够检查日志是每个 DBA 的关键技能——日志提供了关于集群过去的操作、当前正在进行的操作以及发…

数据虚拟化:零数据搬运,实现全域数据的集成和自适应加速

数据虚拟化技术的兴起,与传统数据仓库体系的弊端日益显现有着密切关系。 过去,企业通常会构建数据仓库来存储与加工结构化数据。数据仓库虽然实现了数据的物理集中存储,但过于依赖大量的 ETL 工程师来支持数据的集成、准备、开发与管理。随着…

uniapp小程序src引用服务器图片时全局变量与图片路径拼接

理论上&#xff0c;应该在main.js中定义一个全局变量&#xff0c;然后在页面的<image>标签上的是src直接使用即可 main.js 页面上 看上去挺靠谱的&#xff0c;实际上小程序后台会报一个错 很明显这种方式小程序是不认的&#xff0c;这就头疼了&#xff0c;还想过另外一个…

提高篇(六):利用Processing进行数据艺术创作:从数据获取到视觉表达

提高篇(六):利用Processing进行数据艺术创作:从数据获取到视觉表达 引言 数据艺术是一种结合数据和艺术的创作形式,通过将数据转化为视觉图像,表达出数据背后的故事和美感。Processing作为一种强大的创意编程工具,能够帮助艺术家和设计师将复杂的数据以直观和艺术化的方…

宝藏级-LLM-文档级别向量化问答技术总结

简单且详细的目录 1.简单阶段描述2.阶段展开描述2.1.第一阶段技术:加载文档-读取文档-文本分割(Text splitter)2.1.1.加载读取文档:读取加载的文档内容,通常是将其转化为文本格式2.1.1.1.基于文档解析工具的方法2.1.1.1.1.pdf解析工具2.1.1.1.2.doc、docx解析工具2.1.1.1.3.…

Android 蓝牙概述

一、什么是蓝牙 蓝牙是一种短距离&#xff08;一般10m内&#xff09;无线通信技术。蓝牙技术允许固定和移动设备在不需要电缆的情况下进行通信和数据传输。 “蓝牙”这名称来自10世纪的丹麦国王哈拉尔德(Harald Gormsson)的外号。出身海盗家庭的哈拉尔德统一了北欧四分五裂的国…

【js】input设置focus()不生效

实现功能&#xff1a;点击添加文章标签的时候&#xff0c;输入框聚焦。 页面上&#xff0c;input输入框默认不显示&#xff0c;是display:none; 点击添加按钮后&#xff0c;input输入框才显示。 在js里面直接获取元素进行设置聚焦不成功 。 ∵ focus方法比show方法先执行。j…

docker目录挂载失败:Check if the specified host path exists and is the expected type

docker目录挂载失败&#xff1a;Check if the specified host path exists and is the expected type docker目录挂载命令&#xff0c;其目的是为了达到修改linux上的文件同步到容器上&#xff0c;从而实现修改容器的配置文件。 在docker目录挂载或启动容器时报错&#xff0c…

LeetCode 1193, 45, 48

目录 1193. 每月交易 I题目链接表要求知识点思路代码 45. 跳跃游戏 II题目链接标签思路代码 48. 旋转图像题目链接标签要求思路代码 1193. 每月交易 I 题目链接 1193. 每月交易 I 表 表Transactions的字段为id&#xff0c;country&#xff0c;state&#xff0c;amount和tra…

spring源码初始学习基础-环境

环境&#xff1a;在这里插入代码片 allprojects {repositories {maven { url file:///D:/software/repository} // 本地仓库地址&#xff0c;如果没有依次向下寻找maven { url "https://maven.aliyun.com/repository/public" }mavenLocal()mavenCentral()}buildscri…

2024/6/6随笔

儿童节找了个房子&#xff0c;850元20平&#xff0c;我一开始还以为捡漏了&#xff0c;md&#xff0c;直接痛快交钱&#xff0c;第一次放东西的时候发现它这个单间tmd房间的灯在玄关位置&#xff0c;我真的醉了啊。还好有一个3平方米的小阳台&#xff0c;不然我肯定找房东骂她&…

2年JAVA今日头条3轮面试经历

面头条的时候已经是十月底了。大半个月没有面试&#xff0c;之前准备的知识点比如http状态码之类的记忆性的东西&#xff0c;早就忘光了。 二面的时候问了一堆状态码&#xff0c;全都不记得了。面试官态度很好&#xff0c;跟我说&#xff0c;你现在不记得了&#xff0c;说明你…

CentOS 7.9 安装配置Python2与Python3共存

CentOS 7.9 安装配置Python2与Python3共存 CentOS 7.9默认安装的是Python2.7.5版本, yum仓库中python3的版本是Python3.6.8。当需要更新的Python3版本时&#xff0c;需要手动编译安装。同时CentOS中部分工具如yum依赖Python2&#xff0c;yum安装python3时不会引发依赖问题&…

【Vue】组件通信

文章目录 一、组件之间如何通信二、组件关系分类三、通信解决方案四、父子通信流程五、父向子通信代码示例六、子向父通信代码示例 组件通信&#xff0c;就是指组件与组件之间的数据传递 组件的数据是独立的&#xff0c;无法直接访问其他组件的数据。想使用其他组件的数据&…

k8s学习--kube-proxy的三种工作模式详细解释

kube-proxy 是 Kubernetes 中负责集群中网络规则的组件&#xff0c;它维护网络规则使得 Pod 间的网络通信和访问集群外部的服务成为可能。kube-proxy 支持三种工作模式&#xff1a;userspace 模式、iptables 模式和 ipvs 模式。 快速理解 userspace 模式 实现简单&#xff0c;…

?。。。。。。。。。。。

--超值大礼包&#xff0c;部分原型在线预览地址-- PC端标准化元件库模板&#xff1a; https://axhub.im/pro/db1fd100c40ab6cc/#g1 生鲜电商APP&#xff1a; https://axhub.im/ax9/3ab6ee4196a35d4b/#g1 抖音高保真原型地址&#xff1a; https://axhub.im/pro/56e8362bbc3d4897…

MethodArgumentNotValidException提取关键报错信息返回

问题&#xff1a;报错框架问题 目的&#xff1a;只需要关键提示词&#xff1b; e.message:Validation failed for argument [0] in com.victorlamp.hviot.common.pojo.CommonResult<com.victorlamp.hviot.service.management.entity.thing.Thing> com.victorlamp.hviot…