Python多线程与多进程教程:全面解析、代码案例与优化技巧

news2025/1/13 5:04:36

文章目录

  • 引言
  • 多线程
    • 多线程概述
        • 案例1:使用多线程实现并发下载文件
        • 案例2:使用多线程处理CPU密集型任务
    • 使用`threading`模块
        • 案例1:自定义线程类并启动线程
        • 案例2:使用锁保护共享资源
    • 线程同步与互斥
        • 案例:使用锁实现线程安全的计数器
    • 常见多线程应用场景
        • 案例:使用多线程处理并发请求的服务器
  • 多进程
    • 多进程的创建与启动
        • 创建和启动一个进程,需要进行的操作:
    • 进程间通信
    • 进程池
        • 使用进程池执行任务的基本流程:
    • 多进程异常处理
  • 优化技巧与注意事项
    • 选择高效的数据结构
    • 使用生成器和迭代器
    • 使用适当的算法和数据结构
    • 减少内存和时间的消耗
  • 完结

引言

python 多线程与多进程

多线程与多进程是Python中常用的并发编程实现方式,能够有效提高程序的执行效率。本文将系统介绍多线程与多进程的概念、使用场景以及相关知识点,并通过大量的代码案例进行演示。

多线程

python3 多线程

多线程概述

多线程是指在一个进程内同时执行多个线程,每个线程可以独立执行不同的任务。多线程编程能够充分利用多核处理器的优势,提高程序的并发性和执行效率。

案例1:使用多线程实现并发下载文件

import threading
import requests

# 下载函数
def download_file(url, filename):
    response = requests.get(url)
    with open(filename, 'wb') as f:
        f.write(response.content)

# URL列表
urls = ['http://example.com/file1.txt', 'http://example.com/file2.txt', 'http://example.com/file3.txt']
# 文件名列表
filenames = ['file1.txt', 'file2.txt', 'file3.txt']

# 创建并启动线程
threads = []
for i in range(len(urls)):
    t = threading.Thread(target=download_file, args=(urls[i], filenames[i]))
    t.start()
    threads.append(t)

# 等待所有线程结束
for t in threads:
    t.join()

print("All files have been downloaded.")

案例2:使用多线程处理CPU密集型任务

import threading

# CPU密集型任务
def calculate_factorial(n):
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

# 创建并启动线程
threads = []
for i in range(5):
    t = threading.Thread(target=calculate_factorial, args=(1000,))
    t.start()
    threads.append(t)

# 等待所有线程结束
for t in threads:
    t.join()

print("All calculations have completed.")

使用threading模块

Python提供了threading模块来支持多线程编程。以下是threading模块中常用的几个类和方法:

  • Thread类:表示一个线程对象,可以通过继承该类创建自定义的线程类。
  • start()方法:启动线程,使其处于就绪状态。
  • run()方法:线程启动后运行的方法,你可以在自定义的线程类中重写该方法以实现具体的逻辑。
  • join()方法:等待线程结束,使主线程阻塞,直到该线程执行完成。
  • Lock类:提供简单的锁机制,用于保护多线程对共享资源的访问。
  • Rlock类:可重入锁,可以被同一线程多次获取。
  • Semaphore类:信号量,用于控制对共享资源的并发访问数量。
  • Condition类:条件变量,用于实现线程之间的协调和通信。

案例1:自定义线程类并启动线程

import threading

# 自定义线程类
class MyThread(threading.Thread):
    def run(self):
        # 线程执行的逻辑
        print("Running thread:", self.name)

# 创建并启动线程
t1 = MyThread()
t2 = MyThread()

t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

print("All threads have finished.")

案例2:使用锁保护共享资源

import threading

# 共享资源
shared_resource = 0
lock = threading.Lock()

# 线程函数
def increment():
    global shared_resource
    for _ in range(100000):
        # 获取锁
        lock.acquire()
        shared_resource += 1
        # 释放锁
        lock.release()

# 创建并启动线程
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)

t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

print("Final value of shared_resource:", shared_resource)

线程同步与互斥

在多线程编程中,多个线程同时访问共享资源可能会导致数据不一致或竞态条件问题。为了解决这些问题,需要使用线程同步和互斥机制。

  • 锁(Lock)机制:使用锁可以保证在任意时刻只有一个线程可以访问共享资源,其他线程需要等待锁的释放。
  • 信号量(Semaphore)机制:用于控制对共享资源的访问数量,允许多个线程同时访问。
  • 条件变量(Condition)机制:一种线程之间的通信机制,可以让线程在满足特定条件时等待或继续执行。

案例:使用锁实现线程安全的计数器

import threading

# 线程安全的计数器类
class Counter:
    def __init__(self):
        self.count = 0
        self.lock = threading.Lock()

    def increment(self):
        with self.lock:
            self.count += 1

    def get_count(self):
        return self.count

# 创建并启动线程
counter = Counter()

threads = []
for _ in range(10):
    t = threading.Thread(target=counter.increment)
    t.start()
    threads.append(t)

# 等待所有线程结束
for t in threads:
    t.join()

print("Final count:", counter.get_count())

常见多线程应用场景

多线程在许多应用场景中都能发挥重要作用,其中包括:

  • 网络编程:可以使用多线程处理并发的客户端请求。
  • IO密集型任务:如文件读写、网络请求等,多线程能够显著提高程序的响应速度。
  • 并行计算:利用多线程进行数据分片和并行计算,提高程序的运算速度。

案例:使用多线程处理并发请求的服务器

import socket
import threading

# 处理客户端请求的线程函数
def handle_client(client_sock):
    while True:
        data = client_sock.recv(1024)
        if not data:
            break
        response = "Server response: " + data.decode()
        client_sock.sendall(response.encode())
    client_sock.close()

# 创建服务器套接字
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_addr = ('127.0.0.1', 8000)
server_sock.bind(server_addr)
server_sock.listen()

print("Server listening on:", server_addr)

while True:
    # 接受客户端连接
    client_sock, client_addr = server_sock.accept()
    print("Received connection from:", client_addr)

    # 创建并启动新的线程来处理客户端请求
    t = threading.Thread(target=handle_client, args=(client_sock,))
    t.start()

多进程

python 多进程

多进程的创建与启动

创建和启动一个进程,需要进行的操作:

  1. 导入multiprocessing模块: import multiprocessing

  2. 定义要在进程中执行的函数: 这是一个普通的Python函数,可以包含任意代码逻辑。例如:

def worker():
    # 进程任务逻辑
    pass
  1. 创建进程对象:使用multiprocessing.Process类来创建一个进程对象,并指定要执行的函数。
p = multiprocessing.Process(target=worker)
  1. 启动进程:调用进程对象的start()方法来启动该进程。
p.start()
  1. 等待进程结束:如果希望父进程等待子进程执行完毕后再继续执行,可以调用进程对象的join()方法。
p.join()
  1. 关闭进程:一旦进程执行完毕,可以调用进程对象的close()方法来关闭该进程。
p.close()

进程间通信

多个进程之间可能需要进行数据传递和协调工作。在多进程编程中,常用的进程间通信方式包括管道、队列、共享内存和信号量等。

  • 管道(Pipe):管道提供了一个双向通信的通道,可以通过multiprocessing.Pipe()方法创建管道对象,并使用send()recv()方法发送和接收数据。
parent_conn, child_conn = multiprocessing.Pipe()
  • 队列(Queue):队列提供了一个先进先出(FIFO)的数据结构,可以使用multiprocessing.Queue()类创建队列对象,并使用put()get()方法放入和获取数据。
queue = multiprocessing.Queue()
  • 共享内存(Shared memory):共享内存允许多个进程之间共享数据,可以使用multiprocessing.Valuemultiprocessing.Array来创建共享内存对象。
value = multiprocessing.Value('i', 0)  # 创建一个整数类型的共享内存对象
array = multiprocessing.Array('d', [1.0, 2.0, 3.0])  # 创建一个双精度浮点型数组共享内存对象

进程池

进程池是一种重复利用多个进程来执行一组任务的方法。multiprocessing模块提供了Pool类来实现进程池功能。

使用进程池执行任务的基本流程:

  1. 创建进程池对象:使用multiprocessing.Pool()来创建一个进程池对象。
pool = multiprocessing.Pool()
  1. 执行任务:使用map()方法将任务分配给进程池中的空闲进程,并返回结果。
results = pool.map(task, range(10))
  1. 关闭进程池:在所有任务执行完毕后,调用进程池对象的close()方法来关闭进程池。
pool.close()
  1. 等待进程池结束:调用进程池对象的join()方法等待所有子进程执行完毕。
pool.join()

进程池可以方便地管理多个进程的创建和执行,从而提高程序的效率。

多进程异常处理

在多进程编程中,如果一个进程抛出异常,那么该进程可能会终止并且不会传播异常给父进程。为了能够捕获和处理子进程中抛出的异常,可以使用try-except-finally语句。

以下是一个示例:

import multiprocessing
import time

# 进程函数
def worker():
    try:
        # 进程任务逻辑
        time.sleep(1)
        1 / 0  # 抛出异常
    except Exception as e:
        print("Caught exception in child process:", e)

# 创建并启动进程
p = multiprocessing.Process(target=worker)
p.start()

# 等待进程结束
p.join()

print("All processes have finished.")

示例中,子进程抛出了一个除以零的异常,父进程通过捕获异常来处理错误,并继续执行。

优化技巧与注意事项

python 优化技巧与注意事项

优化技巧和注意事项对于提升程序的性能和效率非常重要。接下来讲解的是一些常见的优化技巧和注意事项.

选择高效的数据结构

选择适合任务需求的高效数据结构可以显著提升程序的性能。

  • 使用字典替代列表进行快速查找:字典使用哈希表实现,在大多数情况下比列表的线性查找更快。
# 示例:使用字典进行快速查找
data = {'apple': 5, 'banana': 2, 'orange': 3}
quantity = data['apple']
print(quantity)  # 输出: 5
  • 使用集合进行高效的成员关系判断:集合使用哈希集实现,可以在常数时间内判断元素是否存在。
# 示例:使用集合进行成员关系判断
fruits = {'apple', 'banana', 'orange'}
if 'banana' in fruits:
    print("banana exists")
  • 使用堆栈或队列数据结构进行快速插入和删除操作:堆栈和队列可以利用列表或collections.deque实现,并提供了高效的插入和删除操作。
# 示例:使用堆栈和队列进行插入和删除操作
stack = []
stack.append(1)  # 入栈
stack.append(2)
item = stack.pop()  # 出栈
print(item)  # 输出: 2

queue = collections.deque()
queue.append(1)  # 入队列
queue.append(2)
item = queue.popleft()  # 出队列
print(item)  # 输出: 1

使用生成器和迭代器

生成器和迭代器可以节省内存并提高代码的可读性和性能。

  • 使用生成器表达式或yield关键字创建生成器对象:生成器可以按需生成数据,而不需要一次性生成所有数据。
# 示例:使用生成器表达式创建一个生成器对象
evens = (x for x in range(10) if x % 2 == 0)
for num in evens:
    print(num)  # 输出: 0, 2, 4, 6, 8
  • 实现可迭代对象和迭代器:自定义类可以实现__iter__()方法返回一个迭代器对象,并在迭代器对象中实现__next__()方法来生成下一个元素。
# 示例:实现可迭代对象和迭代器
class MyIterable:
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __iter__(self):
        return self

    def __next__(self):
        if self.start >= self.end:
            raise StopIteration
        else:
            self.start += 1
            return self.start - 1

my_iterable = MyIterable(0, 5)
for num in my_iterable:
    print(num)  # 输出: 0, 1, 2, 3, 4

使用适当的算法和数据结构

选择适当的算法和数据结构可以显著提高程序的性能。

  • 使用排序算法进行快速查找:对于有序数据,使用二分查找算法可以在对数时间内查找目标元素。
# 示例:使用二分查找算法进行快速查找
def binary_search(sorted_list, target):
    left = 0
    right = len(sorted_list) - 1

    while left <= right:
        mid = (left + right) // 2
        if sorted_list[mid] < target:
            left = mid + 1
        elif sorted_list[mid] > target:
            right = mid - 1
        else:
            return mid

    return -1

data = [2, 5, 8, 12, 16, 23, 38]
index = binary_search(data, 16)
print(index)  # 输出: 4
  • 使用哈希表进行高效的查找和去重:使用哈希函数将键映射到哈希表的索引,可以在常数时间内查找和去重。
# 示例:使用哈希表进行查找和去重
data = ['apple', 'banana', 'orange', 'banana']
distinct_fruits = set(data)
if 'banana' in distinct_fruits:
    print("banana exists")

fruit_counts = {}
for fruit in data:
    if fruit in fruit_counts:
        fruit_counts[fruit] += 1
    else:
        fruit_counts[fruit] = 1
print(fruit_counts)  # 输出: {'apple': 1, 'banana': 2, 'orange': 1}

减少内存和时间的消耗

优化内存和时间的消耗可以提高程序的性能和效率。

  • 避免不必要的数据拷贝:尽量使用原地操作而不是创建新的对象,以减少内存拷贝开销。
# 示例:避免不必要的数据拷贝
data = [1, 2, 3, 4]
squared_data = [x**2 for x in data]  # 不需要创建新列表,可以直接在原地计算平方
  • 使用适当的数据类型减少内存占用:选择合适的数据类型可以减少内存占用。
# 示例:使用适当的数据类型减少内存占用
data = [1, 2, 3, 4]
sum_value = sum(data)  # 使用内置函数sum()计算和时,将整数列表转换为生成器可以减少内存占用
  • 避免重复计算:将计算结果缓存起来,避免重复计算相同的结果。
# 示例:避免重复计算
def fibonacci(n, cache={}):
    if n in cache:
        return cache[n]
    elif n <= 1:
        return n
    else:
        result = fibonacci(n-1) + fibonacci(n-2)
        cache[n] = result  # 缓存计算结果
        return result

fibonacci(10)  # 只需计算一次,并缓存计算结果

完结

全栈若城 python知识分享

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

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

相关文章

css用法总结

1. 块级元素合并时边框重叠问题的解决方案 设置边框2px 红色 如果不做处理&#xff0c;仅仅添加边框则会是这个样子 设置处理后的样式 代码展示 2. 拥有边框的div , hover时的展示效果 代码展示 3. img 和 文字环绕展示 代码展示 设置左浮动即可 4. text-align: center; 可…

Linux——Samba文件共享服务

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。 个人主页&#xff1a;小李会科技的…

Go语言基础-基础语法

前言&#xff1a; \textcolor{Green}{前言&#xff1a;} 前言&#xff1a; &#x1f49e;这个专栏就专门来记录一下寒假参加的第五期字节跳动训练营 &#x1f49e;从这个专栏里面可以迅速获得Go的知识 本文主要是根据今天所学&#xff08;链接放在了最后&#xff09;总结记录的…

please specify ‘programme‘ in launch.json

故障现象&#xff1a; 在windows下点击F5&#xff0c;以运行vscode代码&#xff0c;在屏幕右下角出现这个错误提醒&#xff1b; 故障原因&#xff1a; 在配置文件&#xff08;settings.json或者launch.json&#xff09;中&#xff0c;缺少“program”这个参数配置&#xff1b…

SpringBoot 如何使用 Actuator 进行应用程序监控

SpringBoot 如何使用 Actuator 进行应用程序监控 在现代的应用程序开发中&#xff0c;应用程序监控是非常重要的&#xff0c;因为它可以帮助我们快速发现和解决问题。Spring Boot Actuator 是 Spring Boot 提供的一个强大的监控和管理工具&#xff0c;它可以帮助我们监控和管理…

0003Java程序设计-SSM+JSP现代家庭教育网站

摘 要 本毕业设计的内容是设计并且实现一个基于java技术的现代家庭教育网站。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&#xff0c;java技术和Tomcat网络信息服务作为应用服务器。现代家庭教育网站的功能已基本实现&#xff0c;主要包括主页、个人中心、会员管理、…

Maven如何创建Maven web项目

1、创建一个新的模块: 1.1 使用骨架点一下&#xff0c;这里 1.2 找到maven-archetype-webapp项目&#xff0c;选中点击&#xff0c;一路next就行。 1.3 删除不必要的maven配置&#xff1a;&#xff08;这里我不需要&#xff0c;针对自己情况而定&#xff09; 可以从name这里开…

figma设计软件专业版教育优惠学生使用edu邮箱免费教程

产品介绍 今天一个买家发了一个链接问是否可以用&#xff0c;本站也是第一次见到&#xff0c;就测试了下可以使用教育优惠后准备分享给大家。本站的大多数教育优惠线报其实都是很多网友买家提供的。 Figma是一款用于数字项目的基于云的设计和原型的设计工具软件。 这样做的目…

Python应用实例(一)外星人入侵(二)

1.添加飞船图像 下面将飞船加入游戏中。为了在屏幕上绘制玩家的飞船&#xff0c;我们将加载一幅图像&#xff0c;再使用Pygame方法blit()绘制它。 为游戏选择素材时&#xff0c;务必要注意许可。最安全、最不费钱的方式是使用Pixabay等网站提供的免费图形&#xff0c;无须授权…

强者游戏-敢来挑战否-Amazon DeepRacer League

Amazon DeepRacer中国峰会总决赛 Amazon DeepRacer 自动驾驶赛车名校邀请赛会在6月27日-28日举办的Amazon DeepRacer中国峰会总决赛时同步启动。勇哥的目标是拿个比较好的名词。大家如果有参加这次活动的可以过来一起搞哦。下面我来具体介绍一下这次峰会&#xff0c;以及比赛的…

PyTorch C++ 前端是 PyTorch 机器学习框架的纯 C++ 接口

使用 PyTorch C 前端 PyTorch C 前端是 PyTorch 机器学习框架的纯 C 接口。 虽然 PyTorch 的主要接口自然是 Python&#xff0c;但此 Python API 位于强大的 C 代码库之上&#xff0c;提供基本的数据结构和功能&#xff0c;例如张量和自动微分。 C 前端公开了纯 C 11 API&…

常见面试题之线程基础知识

1. 线程和进程的区别&#xff1f; 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。 当一…

DataStructure01|ArrayList和顺序表

ArrayList与顺序表 1.线性表 ​ 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列… ​ 线性表在逻辑上是线性结构&#xff0c;也就说…

产品设计.从用户体验五要素出发,谈如何设计产品

用户调研--产品定位---产品方案---视觉设计 作者 | 渐渐见减减简https://www.zcool.com.cn/article/ZMTEyNDA2NA.html 用户体验五要素是一种产品分析与设计的方法论&#xff0c;帮助我们以正确方式从0到1设计一款产品。 1 战略层 企业做一个产品前&#xff0c;都要明确几个问题…

多目标樽海鞘算法MATLAB实战(附源码)

今天给大家分享多目标樽海鞘算法&#xff0c;主要从算法原理和代码实战展开。需要了解智能算法、机器学习、深度学习和信号处理相关理论的可以后台私信哦&#xff0c;下一期分享的内容就是你想了解的内容。 一、算法原理 上一篇分享的SSA算法能够驱动salps向食物来源靠近&…

【Flutter】包管理(6)Flutter 状态管理 Provider 深入使用指南

文章目录 一、 前言二、 ProxyProvider 的使用三、 处理异步数据四、 性能优化五、 版本信息六、 总结一、 前言 在我们的上一篇文章中,我们介绍了 Flutter 中 Provider 包的基本使用。 在这篇文章中,我们将深入探讨 Provider 的高级使用方法,包括如何使用 ProxyProvider,…

Green板 和Red板和Nv EVM板比较

001 电源开关、 复位、烧写按钮 G&#xff1a;绿板 K3: Reset press RN K1: Brush RECOVERY button K2: Start button Power ON R: 红板 K3: POWER_KEY K2: FORCE_RECOVERY K1: RESET_KEY 002 USB设计 烧写连接器 G: 绿板 J6&#xff1a;TYPE C 烧写连接器 USB0_DP …

streamlit——搭建作业、文件上传网站(代码编写、服务器部署)

使用streamlit搭建简单的作业提交网站 文章目录 使用streamlit搭建简单的作业提交网站一、引言二、streamlit代码三、搭建到服务器中1、放行安全组2、将代码放到服务器中3、配置依赖4、运行代码 一、引言 由于我平时需要收集各种类型的作业文件。但传统的微信收文件方式很让我…

PyQt5中文手册

PyQt5中文手册 一、介绍 本教程的目的是带领你入门PyQt5。教程内所有代码都在Linux上测试通过。PyQt4 教程是PyQt4的教程&#xff0c;PyQt4是一个Python&#xff08;同时支持2和3&#xff09;版的Qt库。 关于 PyQt5 PyQt5 是Digia的一套Qt5应用框架与python的结合&#xff…

实训五:数据库安全控制 - 授权及回收权限

授权及回收权限 第1关&#xff1a;授权任务描述相关知识MySql系统库中的权限表访问控制的两个阶段&#xff1a;授予的权限等级&#xff1a;MySQL 权限类型grant 语句的基本语法格式revoke 语句的基本语法格式查看权限限制权限 编程要求测试说明参考代码 第2关&#xff1a;授权-…