0

0

Python 中的并发性与线程和多处理

DDD

DDD

发布时间:2024-09-14 08:09:11

|

965人浏览过

|

来源于dev.to

转载

python 中的并发性与线程和多处理

并发是现代编程中的一个重要思想,它允许多个任务同时运行以提高应用程序的性能。

python 中实现并发的方法有多种,其中最著名的是线程和多处理。

在本文中,我们将详细探讨这两种方法,了解它们的工作原理,并讨论何时使用每种方法,以及实际的代码示例。


什么是并发?

在我们讨论线程和多处理之前,了解并发的含义很重要。

立即学习Python免费学习笔记(深入)”;

并发是指一个程序可以同时执行多个任务或进程。

这可以使程序更好地利用资源并运行得更快,特别是当它需要执行诸如读取文件或进行大量计算之类的操作时。

实现并发的方式主要有两种:

  • 并行性:在计算机处理器的不同部分上同时运行多个任务。
  • 并发:在同一时间段内处理多个任务,但不一定在完全相同的时刻。

python 提供了两种主要方式来实现并发:

  • 线程:适用于可以同时管理的任务。
  • 多处理:适用于需要在不同处理器核心上真正同时运行的任务。

python 中的线程

线程允许您在同一进程内运行多个较小的进程单元(称为线程),共享相同的内存空间。

线程比进程更轻,并且它们之间的切换更快。

但是,python 中的线程受全局解释器锁 (gil) 的约束,这确保一次只有一个线程可以执行 python 代码。

线程如何工作

python的线程模块提供了一种简单灵活的方式来创建和管理线程。

让我们从一个基本示例开始:

import threading
import time


def print_numbers():
    for i in range(5):
        print(f"number: {i}")
        time.sleep(1)


# creating a thread
thread = threading.thread(target=print_numbers)

# starting the thread
thread.start()

# wait for the thread to complete
thread.join()

print("thread has finished executing")


# output:
# number: 0
# number: 1
# number: 2
# number: 3
# number: 4
# thread has finished executing

在此示例中:

  • 我们定义了一个函数 print_numbers(),它打印从 0 到 4 的数字,两次打印之间有一秒的延迟。
  • 我们使用 threading.thread() 创建一个线程,并将 print_numbers() 作为目标函数传递。
  • start() 方法开始线程的执行,而 join() 确保主程序等待线程完成后再继续执行。

示例:i/o 密集型任务的线程化

线程对于 i/o 密集型任务特别有用,例如文件操作、网络请求或数据库查询,在这些任务中程序大部分时间都在等待外部资源。

这是一个使用线程模拟下载文件的示例:

import threading
import time


def download_file(file_name):
    print(f"starting download of {file_name}...")
    time.sleep(2)  # simulate download time
    print(f"finished downloading {file_name}")


files = ["file1.zip", "file2.zip", "file3.zip"]

threads = []

# create and start threads
for file in files:
    thread = threading.thread(target=download_file, args=(file,))
    thread.start()
    threads.append(thread)

# ensure all threads have finished
for thread in threads:
    thread.join()

print("all files have been downloaded.")

# output:
# starting download of file1.zip...
# starting download of file2.zip...
# starting download of file3.zip...
# finished downloading file1.zip
# finished downloading file2.zip
# finished downloading file3.zip
# all files have been downloaded.

通过为每个文件下载创建和管理单独的线程,程序可以同时处理多个任务,从而提高整体效率。

代码中关键步骤如下:

  • 定义了一个函数 download_file 来模拟下载过程。
  • 创建文件名列表来表示需要下载的文件。
  • 对于列表中的每个文件,都会创建一个新线程,并以 download_file 作为其目标函数。每个线程在创建后立即启动并添加到线程列表中。
  • 主程序使用 join() 方法等待所有线程完成,确保程序在所有下载完成之前不会继续进行。

线程的局限性

虽然线程可以提高 i/o 密集型任务的性能,但它也有局限性:

  • 全局解释器锁 (gil):对于 cpu 密集型任务,gil 限制一次只能执行一个线程,从而限制了多核处理器中线程的有效性。
  • 竞争条件:由于线程共享相同的内存空间,不正确的同步可能会导致竞争条件,程序的结果取决于线程的时间。
  • 死锁:线程相互等待释放资源可能会导致死锁,从而无法取得任何进展。

python 中的多处理

多处理通过使用单独的进程而不是线程来解决线程的局限性。

每个进程都有自己的内存空间和python解释器,允许在多核系统上实现真正的并行。

EnablePPA中小学绩效考核系统2.0
EnablePPA中小学绩效考核系统2.0

无论从何种情形出发,在目前校长负责制的制度安排下,中小学校长作为学校的领导者、管理者和教育者,其管理水平对于学校发展的重要性都是不言而喻的。从这个角度看,建立科学的校长绩效评价体系以及拥有相对应的评估手段和工具,有利于教育行政机关针对校长的管理实践全过程及其结果进行测定与衡量,做出价值判断和评估,从而有利于强化学校教学管理,提升教学质量,并衍生带来校长转变管理观念,提升自身综合管理素质。

下载

这使得多重处理成为需要大量计算的任务的理想选择。

多重处理的工作原理

python 中的多处理模块允许您轻松创建和管理进程。

让我们从一个基本示例开始:

import multiprocessing
import time


def print_numbers():
    for i in range(5):
        print(f"number: {i}")
        time.sleep(1)


if __name__ == "__main__":
    # creating a process
    process = multiprocessing.process(target=print_numbers)

    # starting the process
    process.start()

    # wait for the process to complete
    process.join()

    print("process has finished executing")

# output:
# number: 0
# number: 1
# number: 2
# number: 3
# number: 4
# process has finished executing

此示例与线程示例类似,但具有进程。

请注意,进程的创建和管理与线程类似,但由于进程运行在单独的内存空间中,因此它们是真正并发的,并且可以运行在不同的 cpu 核心上。

示例:cpu 密集型任务的多处理

多处理对于受 cpu 限制的任务特别有用,例如数值计算或数据处理。

这是一个使用多个进程计算数字平方的示例:

import multiprocessing


def compute_square(number):
    return number * number


if __name__ == "__main__":
    numbers = [1, 2, 3, 4, 5]

    # create a pool of processes
    with multiprocessing.pool() as pool:
        # map function to numbers using multiple processes
        results = pool.map(compute_square, numbers)

    print("squares:", results)

# output:
# squares: [1, 4, 9, 16, 25]

以下是代码中的关键步骤:

  • 函数compute_square被定义为接受一个数字作为输入并返回其平方。
  • if name == "main": 块中的代码确保它仅在直接执行脚本时运行。
  • 定义了一个数字列表,将对其进行平方。
  • 工作进程池是使用 multiprocessing.pool() 创建的。
  • map 方法用于将compute_square函数应用于列表中的每个数字,将工作负载分配到多个进程。

进程间通信(ipc)

由于每个进程都有自己的内存空间,进程之间共享数据需要进程间通信(ipc)机制。

多处理模块提供了一些用于ipc的工具,例如queue、pipe和value。

这是一个使用队列在进程之间共享数据的示例:

import multiprocessing


def worker(queue):
    # Retrieve and process data from the queue
    while not queue.empty():
        item = queue.get()
        print(f"Processing {item}")


if __name__ == "__main__":
    queue = multiprocessing.Queue()

    # Add items to the queue
    for i in range(10):
        queue.put(i)

    # Create a pool of processes to process the queue
    processes = []
    for _ in range(4):
        process = multiprocessing.Process(target=worker, args=(queue,))
        processes.append(process)
        process.start()

    # Wait for all processes to complete
    for process in processes:
        process.join()

    print("All processes have finished.")


# Output:
# Processing 0
# Processing 1
# Processing 2
# Processing 3
# Processing 4
# Processing 5
# Processing 6
# Processing 7
# Processing 8
# Processing 9
# All processes have finished.

在此示例中:

  • defworker(queue):定义一个以队列作为参数的函数worker。该函数检索并处理队列中的项目,直到队列为空。
  • if name == "main":: 确保以下代码仅在直接执行脚本时运行,而不是作为模块导入时运行。
  • queue = multiprocessing.queue():创建用于进程间通信的队列对象。
  • for i in range(10):queue.put(i):将项目(数字 0 到 9)添加到队列中。
  • processes = []:初始化一个空列表来存储进程对象。
  • for _ in range(4) 循环:创建四个工作进程。
  • process = multiprocessing.process(target=worker, args=(queue,)):创建一个以worker为目标函数的新进程,并将队列作为参数传递。
  • processes.append(process):将进程对象添加到进程列表中。
  • process.start():启动进程。
  • 进程中进程的 for 循环:使用 join() 方法等待每个进程完成。

多重处理的挑战

虽然多处理提供了真正的并行性,但它也面临着一系列挑战:

  • 更高的开销:由于内存空间是独立的,创建和管理进程比线程更耗费资源。
  • 复杂性:进程之间的通信和同步比线程更复杂,需要ipc机制。
  • 内存使用:每个进程都有自己的内存空间,导致与线程相比内存占用更高。

何时使用线程与多处理

在线程和多处理之间进行选择取决于您正在处理的任务类型:

使用线程:

  • 对于需要大量等待的任务,例如网络操作或读/写文件(i/o 密集型任务)。
  • 当您需要在任务之间共享内存并可以管理竞争条件等潜在问题时。
  • 实现轻量级并发,无需创建多个进程的额外开销。

使用多重处理:

  • 对于需要大量计算或数据处理的任务(cpu 密集型任务),并且可以从同时在多个 cpu 核心上运行中受益。
  • 当您需要真正的并行性并且线程中的全局解释器锁(gil)成为限制时。
  • 适用于可以独立运行且不需要频繁通信或共享内存的任务。

结论

python 中的并发是让应用程序运行得更快的强大方法。

线程非常适合需要大量等待的任务,例如网络操作或读/写文件,但由于全局解释器锁(gil)的原因,它对于需要大量计算的任务并不那么有效。

另一方面,多处理允许真正的并行性,使其非常适合 cpu 密集型任务,尽管它会带来更高的开销和复杂性。

无论您是处理数据、处理多个网络请求,还是进行复杂的计算,python 的线程和多重处理工具都能为您提供所需的功能,使您的程序尽可能高效、快速。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

778

2023.08.22

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

523

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

87

2025.12.01

append用法
append用法

append是一个常用的命令行工具,用于将一个文件的内容追加到另一个文件的末尾。想了解更多append用法相关内容,可以阅读本专题下面的文章。

344

2023.10.25

python中append的用法
python中append的用法

在Python中,append()是列表对象的一个方法,用于向列表末尾添加一个元素。想了解更多append的更多内容,可以阅读本专题下面的文章。

1074

2023.11.14

python中append的含义
python中append的含义

本专题整合了python中append的相关内容,阅读专题下面的文章了解更多详细内容。

176

2025.09.12

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

0

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号