Python 多线程

Python 多线程简介

Python 是当今最受欢迎和多功能的编程语言之一,广泛应用于各个行业,包括 web 开发、机器学习和数据科学。鉴于其在相关领域(如机器学习和大数据)中的广泛应用和高需求,Python 已经超越 Java 成为顶级编程语言。

在本文中,我们将介绍 Python 多线程及其工作原理。我们将涵盖以下内容:

  1. 什么是多线程?
  2. 什么是进程
  3. 多线程的优势
  4. 守护线程(Daemon Thread)
  5. Python 多线程函数
    • threading.active_count()
    • threading.main_thread()
    • threading.Timer()
  6. 使用锁进行同步

什么是多线程?

多线程是指程序中可以独立于其他部分并发执行的一系列指令。

可以将它们视为进程中的不同单元,这些单元在被调度时可以独立完成任务。

当线程需要等待缓慢的外部操作(如网络请求或磁盘访问)完成时,它们会暂时休眠,从而使调度器可以将时间分配给其他线程执行。

什么是进程?

进程是计算机程序的一个可执行实例。

通常,一个进程是在单个控制流序列中执行的。

进程是操作系统分配资源的基本单位,每个进程包含一个或多个线程。

进程之间是隔离的,每个进程拥有自己的内存空间和系统资源。

多线程的优势

  1. 提高性能

    • 多核处理器:多线程程序在多核处理器系统上可以并行执行多个任务,从而显著提高性能。
    • I/O 绑定任务:多线程特别适用于 I/O 绑定任务,如网络请求和磁盘访问。当一个线程等待 I/O 操作完成时,其他线程可以继续执行,充分利用 CPU 时间。
  2. 资源共享

    • 共享内存:同一个进程中的线程可以共享内存,包括全局变量。如果一个线程修改了全局变量的值,这些更改对所有线程都可见,简化了数据共享和通信。

基本的 Python 多线程程序

以下代码是基本的 Python 多线程程序,我们导入了 threading 模块,并创建了一个名为 t 的线程。这个线程 t 将运行 show 函数。

python 复制代码
import threading

def show():
    print(f"Thread {threading.current_thread().name} is running")

# 创建一个线程
t = threading.Thread(target=show, name="MyThread")

# 启动线程
t.start()

# 等待线程完成
t.join()

print("Main thread has completed")

守护线程 (Daemon Thread)

守护线程是一种在后台运行的线程,它不会阻止主程序的退出。当主程序的所有非守护线程(即用户线程)结束时,守护线程也会自动终止。守护线程通常用于执行一些辅助性任务,如定期保存数据、监控系统状态等。

示例

下面是一个简单的 Python 示例,展示了如何创建和使用守护线程:

python 复制代码
import threading
import time

def background_task():
    count = 0
    while True:
        print(f"Background task {count}")
        count += 1
        time.sleep(1)

# 创建一个守护线程
t = threading.Thread(target=background_task, daemon=True)
t.name = "BackgroundThread"

# 启动线程
t.start()

# 主程序继续执行
print("Main thread is running...")

# 让主程序运行一段时间
time.sleep(5)

print("Main thread has completed")

关键点

  • 守护线程 :通过设置 daemon=True,线程成为守护线程。当主程序的所有非守护线程结束时,守护线程会自动终止。
  • 无限循环:守护线程通常用于执行无限循环的任务,这些任务不需要在主程序结束时显式地停止。
  • 线程名称 :可以通过 t.name 设置线程的名称,方便调试和日志记录。

Python 线程相关函数

Python 的 threading 模块提供了多种功能来管理和控制线程。以下是一些常用的线程相关函数及其示例:

1. threading.active_count()

这个函数返回当前正在执行的线程数量。

示例

python 复制代码
import threading

def show():
    print(f"Thread {threading.current_thread().name} is running")

# 创建并启动两个线程
t1 = threading.Thread(target=show, name="Thread1")
t2 = threading.Thread(target=show, name="Thread2")

t1.start()
t2.start()

# 输出当前活跃线程的数量
print(f"Number of active threads: {threading.active_count()}")

# 等待所有线程完成
t1.join()
t2.join()

输出

Thread Thread1 is running
Thread Thread2 is running
Number of active threads: 3
Main thread has completed
2. threading.main_thread()

这个函数返回程序的主线程对象。

示例

python 复制代码
import threading

def show():
    print(f"Thread {threading.current_thread().name} is running")

# 创建并启动一个线程
t = threading.Thread(target=show, name="MyThread")
t.start()

# 获取主线程
main_thread = threading.main_thread()
print(f"Main thread name: {main_thread.name}")

# 等待线程完成
t.join()

输出

Thread MyThread is running
Main thread name: MainThread
3. threading.Timer()

这个函数用于创建一个新的线程,并指定该线程在一定时间后启动。一旦启动,它会调用指定的函数。

示例

python 复制代码
import threading
import time

def delayed_task():
    print("Delayed task executed")

# 创建一个定时器线程,3秒后执行 delayed_task 函数
timer = threading.Timer(3, delayed_task)
timer.start()

# 主程序继续执行
print("Main thread is running...")

# 让主程序运行一段时间
time.sleep(5)

print("Main thread has completed")

输出

Main thread is running...
Delayed task executed
Main thread has completed

代码解释

  1. threading.active_count()

    • 该函数返回当前正在执行的线程数量。
    • 在示例中,我们创建并启动了两个线程,然后输出当前活跃线程的数量。
  2. threading.main_thread()

    • 该函数返回程序的主线程对象。
    • 在示例中,我们获取了主线程的名称并输出。
  3. threading.Timer()

    • 该函数用于创建一个定时器线程,指定延迟时间和要执行的函数。
    • 在示例中,我们创建了一个定时器线程,3秒后执行 delayed_task 函数。

使用锁进行同步

在多线程编程中,锁(Lock)是一种重要的同步机制,用于确保多个线程不会同时访问共享资源,从而避免竞态条件(race conditions)。Python 的 threading 模块提供了 Lock 类来实现这一功能。Lock 类有两个主要方法:acquire()release()

方法说明
  1. acquire()

    • 用于获取锁。如果锁已经被其他线程持有,则调用 acquire() 的线程会被阻塞,直到锁被释放。
    • 可以选择性地传递一个超时参数 timeout,以防止线程无限期地等待锁。
  2. release()

    • 用于释放锁。如果锁未被当前线程持有,则会引发 RuntimeError 异常。
示例

下面是一个使用锁来同步两个线程的简单示例:

python 复制代码
import threading

# 共享资源
shared_resource = 0

# 创建一个锁对象
lock = threading.Lock()

def increment():
    global shared_resource
    for _ in range(1000000):
        lock.acquire()
        shared_resource += 1
        lock.release()

def decrement():
    global shared_resource
    for _ in range(1000000):
        lock.acquire()
        shared_resource -= 1
        lock.release()

# 创建两个线程
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=decrement)

# 启动线程
t1.start()
t2.start()

# 等待线程完成
t1.join()
t2.join()

# 输出最终的共享资源值
print(f"Final value of shared resource: {shared_resource}")

代码解释

  1. 导入 threading 模块

    python 复制代码
    import threading
  2. 定义共享资源

    python 复制代码
    shared_resource = 0
  3. 创建锁对象

    python 复制代码
    lock = threading.Lock()
  4. 定义 increment 函数

    python 复制代码
    def increment():
        global shared_resource
        for _ in range(1000000):
            lock.acquire()
            shared_resource += 1
            lock.release()
    • 这个函数会增加 shared_resource 的值 1000000 次。每次操作前先获取锁,操作完成后释放锁。
  5. 定义 decrement 函数

    python 复制代码
    def decrement():
        global shared_resource
        for _ in range(1000000):
            lock.acquire()
            shared_resource -= 1
            lock.release()
    • 这个函数会减少 shared_resource 的值 1000000 次。每次操作前先获取锁,操作完成后释放锁。
  6. 创建并启动线程

    python 复制代码
    t1 = threading.Thread(target=increment)
    t2 = threading.Thread(target=decrement)
    
    t1.start()
    t2.start()
  7. 等待线程完成

    python 复制代码
    t1.join()
    t2.join()
  8. 输出最终的共享资源值

    python 复制代码
    print(f"Final value of shared resource: {shared_resource}")

预期输出

由于 incrementdecrement 每个都执行 1000000 次,并且使用锁来同步,最终的 shared_resource 应该是 0。

注意事项

  • 死锁:如果一个线程获取了多个锁,但没有按正确的顺序释放,可能会导致死锁。使用锁时要小心,确保每个锁都能正确地被释放。
  • 性能:频繁地获取和释放锁可能会影响性能,因此在实际应用中需要权衡同步的需求和性能的影响。

总结

在这篇文章中,我们探讨了 Python 多线程的基本概念。我们学习了与多线程相关的不同函数和对象,包括:

  1. threading.active_count()

    • 用于获取当前正在执行的线程数量。
  2. threading.main_thread()

    • 用于获取程序的主线程对象。
  3. threading.Timer()

    • 用于创建一个定时器线程,指定延迟时间后执行特定的函数。
  4. 锁(Lock)

    • 用于同步多个线程,避免竞态条件。锁的主要方法有 acquire()release()

通过这些基本概念和示例,你可以更好地理解和使用 Python 的多线程功能来开发高效的并发应用程序。

相关推荐
shinelord明3 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
游客5208 分钟前
opencv中的各种滤波器简介
图像处理·人工智能·python·opencv·计算机视觉
Monly2110 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu11 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee202111 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
7yewh14 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
Dontla16 分钟前
vscode怎么设置anaconda python解释器(anaconda解释器、vscode解释器)
ide·vscode·python
waicsdn_haha25 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc27 分钟前
C++ 日志输出
开发语言·c++·算法
qq_4335545436 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++