首页 > 系统相关 >Python 课程8-多线程编程和多进程编程

Python 课程8-多线程编程和多进程编程

时间:2024-09-14 20:49:25浏览次数:9  
标签:__ start Python 编程 threading 线程 进程 多线程 multiprocessing

前言

        在现代编程中,处理并发任务是提高程序性能的关键之一。Python 提供了 多线程(threading)多进程(multiprocessing) 两种方式来实现并发编程。多线程适用于 I/O 密集型任务,而多进程则更适合 CPU 密集型任务。通过这两种技术,你可以高效地处理大规模数据、加速程序执行并优化资源利用。

        在本篇详细教程中,我们将讨论如何使用 Python 的 threading 模块实现多线程,以及如何使用 multiprocessing 库实现多进程,帮助你掌握并发编程的基础和应用场景。        


目录

多线程编程(threading)

  1. 什么是多线程?
  2. 使用 Thread() 创建线程
  3. start() 和 join():启动和等待线程
  4. 线程间共享数据
  5. 锁(Locks):避免线程冲突
  6. 示例:多线程处理 I/O 操作

多进程编程(multiprocessing)

  1. 什么是多进程?
  2. 使用 Process() 创建进程
  3. 进程池(Pool)管理多个进程
  4. map() 和 apply_async():并行任务执行
  5. 进程间通信(Queue 和 Pipe)
  6. 示例:多进程计算密集型任务

多线程编程(threading)

1. 什么是多线程?

        多线程是指在一个进程中同时运行多个线程,每个线程执行不同的任务,共享进程的内存空间。多线程适用于I/O密集型任务,如文件读写、网络请求等,可以提高程序的并发性和响应速度。

特点:

  • 共享内存空间,数据共享和通信方便。
  • 线程间切换速度快,开销小。
  • 受全局解释器锁(GIL)影响,CPU密集型任务并不能真正并行。

2. 使用 Thread() 创建线程

threading模块提供了创建线程的类和方法。

import threading  # 导入 threading 模块

def task():
    print("这是一个线程任务")

# 创建线程对象,target参数指定线程要执行的函数
thread = threading.Thread(target=task)

# 启动线程
thread.start()

代码解析:

  • import threading:导入线程模块。
  • def task():定义线程要执行的函数。
  • threading.Thread(target=task):创建线程对象。
  • thread.start():启动线程,开始执行任务。

3. start() 和 join():启动和等待线程

  • start():启动线程,使其开始执行。
  • join():阻塞主线程,等待子线程完成。
import threading
import time

def task(name):
    print(f"线程 {name} 开始")
    time.sleep(2)
    print(f"线程 {name} 结束")

# 创建多个线程
threads = []
for i in range(3):
    thread = threading.Thread(target=task, args=(i,))
    threads.append(thread)
    thread.start()

# 等待所有线程完成
for thread in threads:
    thread.join()

print("所有线程已完成")

 代码解析:

  • args=(i,):传递参数给线程函数。
  • threads.append(thread):将线程对象添加到列表中,便于管理。
  • thread.join():主线程等待子线程完成。

4. 线程间共享数据

线程之间可以共享全局变量,但需要注意线程安全问题。

import threading

counter = 0  # 全局变量

def increment():
    global counter
    for _ in range(100000):
        counter += 1

# 创建两个线程
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)

# 启动线程
thread1.start()
thread2.start()

# 等待线程完成
thread1.join()
thread2.join()

print(f"最终计数器的值为:{counter}")

注意:由于线程争用,最终计数器的值可能不等于预期的200000。这是因为多个线程同时修改共享数据,导致数据竞争。


5. 锁(Locks):避免线程冲突

使用锁机制可以确保同一时间只有一个线程访问共享数据,避免数据竞争。

import threading

counter = 0
lock = threading.Lock()  # 创建锁对象

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

# 创建两个线程
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)

# 启动线程
thread1.start()
thread2.start()

# 等待线程完成
thread1.join()
thread2.join()

print(f"最终计数器的值为:{counter}")

 代码解析:

  • lock = threading.Lock():创建一个锁对象。
  • lock.acquire():请求获取锁,若锁已被占用,则等待。
  • lock.release():释放锁,供其他线程使用。

6. 示例:多线程处理 I/O 操作

import threading
import requests

urls = [
    'https://www.python.org',
    'https://www.google.com',
    'https://www.github.com',
    # 更多的URL
]

def fetch_content(url):
    response = requests.get(url)
    print(f"{url} 的响应码:{response.status_code}")

threads = []
for url in urls:
    thread = threading.Thread(target=fetch_content, args=(url,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

print("所有请求已完成")

 代码解析:

  • requests.get(url):发送HTTP GET请求。
  • threading.Thread(target=fetch_content, args=(url,)):为每个URL创建一个线程。
  • 适用于I/O密集型任务,提高程序响应速度。

多进程编程(multiprocessing)

1. 什么是多进程?

多进程是指同时运行多个进程,每个进程都有独立的内存空间。多进程适用于CPU密集型任务,如计算、图像处理等,能有效利用多核CPU,提高程序性能。

特点:

  • 进程间内存独立,数据不共享,安全性高。
  • 能够真正实现并行,充分利用多核CPU。
  • 进程创建和切换开销较大。

2. 使用 Process() 创建进程

import multiprocessing

def task(name):
    print(f"进程 {name} 开始")
    # 执行任务
    print(f"进程 {name} 结束")

if __name__ == '__main__':
    process = multiprocessing.Process(target=task, args=('A',))
    process.start()
    process.join()
    print("主进程结束")

 代码解析:

  • multiprocessing.Process(target=task, args=('A',)):创建进程对象。
  • process.start():启动进程。
  • process.join():等待进程完成。
  • 注意:在Windows系统中,必须将进程创建代码放在if __name__ == '__main__':下。

3. 进程池(Pool)管理多个进程

import multiprocessing
import time

def task(name):
    print(f"任务 {name} 开始")
    time.sleep(2)
    print(f"任务 {name} 结束")

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)  # 创建拥有3个进程的进程池
    for i in range(5):
        pool.apply_async(task, args=(i,))
    pool.close()  # 关闭进程池,不能再添加新任务
    pool.join()   # 等待所有任务完成
    print("所有任务已完成")

 代码解析:

  • multiprocessing.Pool(processes=3):创建进程池,最大进程数为3。
  • pool.apply_async(task, args=(i,)):异步提交任务到进程池。
  • pool.close():关闭进程池,不再接受新任务。
  • pool.join():主进程等待进程池中的任务完成。

4. map() 和 apply_async():并行任务执行

使用 map() 方法

import multiprocessing

def square(x):
    return x * x

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    results = pool.map(square, range(10))
    print(results)

 代码解析:

  • pool.map(square, range(10)):将range(10)中的每个元素传递给square函数,并行计算。

使用 apply_async() 方法

import multiprocessing

def square(x):
    return x * x

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    results = []
    for i in range(10):
        result = pool.apply_async(square, args=(i,))
        results.append(result)
    pool.close()
    pool.join()
    print([r.get() for r in results])

 代码解析:

  • pool.apply_async():异步地将任务提交到进程池。
  • result.get():获取异步执行的结果。

5. 进程间通信(Queue 和 Pipe)

使用 Queue

import multiprocessing

def producer(queue):
    for item in range(5):
        queue.put(item)
        print(f"生产者生产了:{item}")

def consumer(queue):
    while True:
        item = queue.get()
        if item is None:
            break
        print(f"消费者消费了:{item}")

if __name__ == '__main__':
    queue = multiprocessing.Queue()
    p = multiprocessing.Process(target=producer, args=(queue,))
    c = multiprocessing.Process(target=consumer, args=(queue,))

    p.start()
    c.start()

    p.join()
    queue.put(None)  # 发送终止信号
    c.join()

 代码解析:

  • multiprocessing.Queue():创建进程间共享的队列。
  • queue.put(item):将数据放入队列。
  • queue.get():从队列中获取数据。

使用 Pipe

import multiprocessing

def sender(conn):
    conn.send("你好,消费者")
    conn.close()

def receiver(conn):
    message = conn.recv()
    print(f"接收到的信息:{message}")

if __name__ == '__main__':
    parent_conn, child_conn = multiprocessing.Pipe()
    s = multiprocessing.Process(target=sender, args=(parent_conn,))
    r = multiprocessing.Process(target=receiver, args=(child_conn,))

    s.start()
    r.start()

    s.join()
    r.join()

 代码解析:

  • multiprocessing.Pipe():创建一个管道,返回两个连接对象。
  • conn.send():发送数据。
  • conn.recv():接收数据。

6. 示例:多进程计算密集型任务

import multiprocessing
import math
import time

def compute(start, end):
    result = 0
    for i in range(start, end):
        result += math.sqrt(i)
    return result

if __name__ == '__main__':
    start_time = time.time()
    cpu_count = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=cpu_count)

    total_numbers = 10000000
    chunk_size = total_numbers // cpu_count
    tasks = []

    for i in range(cpu_count):
        start = i * chunk_size
        end = (i + 1) * chunk_size if i != cpu_count - 1 else total_numbers
        tasks.append(pool.apply_async(compute, args=(start, end)))

    pool.close()
    pool.join()

    total = sum([task.get() for task in tasks])
    print(f"计算结果:{total}")
    print(f"耗时:{time.time() - start_time} 秒")

 代码解析:

  • cpu_count = multiprocessing.cpu_count():获取CPU核心数。
  • 将计算任务分割成多个子任务,分配给不同的进程执行。
  • pool.apply_async(compute, args=(start, end)):异步提交计算任务。
  • sum([task.get() for task in tasks]):汇总各进程的计算结果。

结论

通过本教程,我们深入学习了Python中的多线程和多进程编程:

  • 多线程编程(threading):

    • 理解了什么是多线程,以及如何创建和管理线程。
    • 学会了使用锁机制避免线程间的数据竞争。
    • 了解了多线程在I/O密集型任务中的应用。
  • 多进程编程(multiprocessing):

    • 掌握了多进程的概念,能创建和管理进程。
    • 学习了进程池的使用,提高了多进程编程的效率。
    • 了解了进程间通信的方法,如队列和管道。
    • 认识到多进程在CPU密集型任务中的优势。

        通过合理地使用多线程和多进程,可以显著提升程序的性能和效率。希望本教程能帮助您深入理解并发编程的核心概念,并在实际项目中加以应用。

标签:__,start,Python,编程,threading,线程,进程,多线程,multiprocessing
From: https://blog.csdn.net/tim654654/article/details/142266142

相关文章

  • PyCharm修改背景颜色、修改字体大小+Python常用快捷键+Python常见的运算符
    文章目录PyCharm软件的使用1.修改背景颜色和字体大小1.1修改背景颜色1.2修改字体大小2.常用的快捷键3.常见的运算符3.1算术运算符3.2赋值运算符3.3比较运算符3.4逻辑运算符PyCharm软件的使用1.修改背景颜色和字体大小1.1修改背景颜色1.2修改字体大......
  • python容器四之字典
    文章目录1.字典介绍2.使用字典3.字典的常见操作3.1添加元素3.2删除元素3.3修改元素3.4查找元素4.字典遍历方法4.1遍历字典元素5.公共运算符6.公共方法1.字典介绍先来看看现实生活中的字典。我们知道,可以应用字典来查找汉字。在这里插入图片描述接着......
  • Day09.面向对象编程OOP(1)
    面向对象编程OOP面向过程&面向对象面向过程思想步骤清晰简单,第一步做什么,第二步做什么......面对过程适合处理一些较为简单的问题面向对象思想物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后才对某个分类下的细节进行面向过......
  • 利用Python与Bokeh创建动态交互数据可视化
    Bokeh是一个用于创建交互式和动态数据可视化的强大工具,它可以帮助你在Python中展示数据的变化趋势、模式和关联性。本文将介绍如何使用Bokeh库在Python中创建动态数据可视化,并提供代码示例以供参考。Bokeh简介Bokeh是一个开源的Python可视化库,它允许用户创建交互式的图......
  • 基于Python+数据可视化大屏+大数据爬虫的短视频内容理解与可视化推荐平台设计和实现(
    博主介绍:✌全网粉丝50W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、P......
  • python第二次课(python基础)
    Python注释单行注释:只能注释一行内容单行注释使用#多行注释:可以注释多行内容多行注释使用三个单引号或者三个双引号都可以文档注释:注释可以生成文档,一般不允许压缩。使用的多行注释,只是有特定的要求字符串的重复问题在python中可以使用*来表示字符串的重复次数,乘数......
  • 基础python超级常用的四种可视化函数库
    可视化的概念可视化是指将数据或信息转换为图形表示形式的过程,以便更容易理解和分析。通过可视化,可以将复杂的概念、大量数据或抽象信息转化为直观的图形,使人们能够更快地洞察数据中的模式、趋势和异常情况。数据可视化是数据科学、统计学、信息设计等多个领域的交叉学科,它不......
  • 入门级小白超实用的python爬虫爬取网页图片
    图像作为信息传播的重要载体,在日常生活和各行各业的应用越来越广泛。网络图片爬取成为了数据挖掘和分析领域的一项重要技术。本文将探讨在网络环境中爬取图片的实现步骤以及代码。效果展示代码运行后,输入关健字等待片刻后桌面会自动创建一个名为picture的文件夹随后开始爬......
  • Python基础语法(2)
    顺序语句默认情况下,Python的代码执行顺序是按照从上到下的顺序,依次执行的print("1")print("2")print("3")执行结果一定为“123”,而不会出现“321”或者“132” 等,这种按照顺序执行的代码,我们称为顺序语句这个顺序是很关键的,编程是一件明确无歧义的事情,安排......
  • Python基础语法(1)下
    输入输出和用户交互程序需要和用户进行交互。用户把信息传递给程序的过程,称为"输入",也就是用户给计算机下命令就叫做输入。程序把结果展示给用户的过程,称为"输出",也就是计算机在向用户汇报工作。输入输出的最基本的方法就是控制台,用户通过控制台输入一些字符串,程序再通......