【Python多线程】的进阶讲解

news/2024/9/20 6:46:00

Python多线程

  • 1. 前言
  • 2. threading 模块的基本用法
  • 3. Thread类
  • 4. 锁(Locks)
  • 5. 守护线程(Daemon Threads)
  • 6. 运用场景
  • 7. 弊端

1. 前言

Python中的多线程通过threading模块来实现,它允许你并发执行多个线程,线程是操作系统能够独立调度的最小单位,它通常被用来执行并行任务。

在解释Python的多线程之前,需要注意的是,由于全局解释器锁(Global Interpreter Lock,GIL)的存在,CPython(Python的主要实现版本)中的多线程通常不能在多个CPU核心中并行执行,GIL确保一次只有一个线程在Python对象上执行操作,防止并发访问导致的状态不一致。因此,Python的多线程更适用于I/O密集型任务而非CPU密集型任务。

2. threading 模块的基本用法

以下是使用threading模块创建和启动一个线程的基本例子:

import threading
import time

# 定义一个函数用于线程执行
def my_function(arg1, arg2):
    for i in range(arg1, arg2):
        print(f"Thread running: {i}")
        time.sleep(1) # 模拟耗时操作

# 创建线程
thread = threading.Thread(target=my_function, args=(1, 10))

# 启动线程
thread.start()

# 在主线程中继续执行其他操作
for i in range(20, 25):
    print(f"Main thread running: {i}")
    time.sleep(1)

# 等待直到线程完成
thread.join()

3. Thread类

threading模块里,Thread是一个代表线程的类,你可以创建一个Thread类的实例并调用它的start()方法来运行新线程。每个Thread可以运行一个函数或方法。

除了直接使用threading.Thread,你也可以通过继承Thread类来定义新的线程子类,重写其中的run()方法:

class MyThread(threading.Thread):
    def __init__(self, arg1, arg2):
        super().__init__()
        self.arg1 = arg1
        self.arg2 = arg2

    def run(self):
        for i in range(self.arg1, self.arg2):
            print(f"Running from the extended thread class: {i}")
            time.sleep(1)

# 使用自定义线程类
thread = MyThread(1, 5)
thread.start()
thread.join()

4. 锁(Locks)

锁是一个同步原语,用于防止多个线程同时访问共享资源,在Python中,你可以使用threading.Lock()来创建一个锁。锁有两个基本方法,acquire()release()。当一个线程通过调用acquire()获得了锁,它会阻止其他线程获取直到它调用release()释放锁。

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

# 在需要访问共享资源前获取锁
lock.acquire()

# 访问共享资源
# ...

# 完成共享资源的访问后释放锁
lock.release()

可以使用 with 语句简化以上模式,这样可以保证锁被正确释放:

with lock:
    # 访问共享资源
    # ...

5. 守护线程(Daemon Threads)

守护线程是一种特殊的线程,它在主线程退出时也会随之退出,与常规线程相比,守护线程不用等待它完成才能退出程序。通过设置线程的daemon属性为True,可以将线程声明为守护线程:

thread = threading.Thread(target=my_function, args=(1, 10))
thread.daemon = True
thread.start()

6. 运用场景

在Python中,多线程经常被用于处理I/O密集型任务,例如文件读写、网络通讯等等。对于CPU密集型任务,多进程通常是更好的选择。

7. 弊端

由于GIL的存在,在CPython的多线程程序不会真正地并行执行多线程,即使在多核CPU上。为了克服这个限制,可以考虑使用multiprocessing模块,这个模块通过创建多个进程来实现真正的并行计算(每个进程有自己的GIL)。当然,每个场景下都需要仔细考虑是否适合多线程、多进程或者其他解决方案,比如异步编程(asyncio)或者其他并发框架(如concurrent.futures)。


http://lihuaxi.xjx100.cn/news/2108834.html

相关文章

力扣_动态规划4—最大正方形

题目 在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵 m a t r i x matrix matrix 内,找到只包含 ‘1’ 的最大正方形,并返回其面积。 方法 创建二维 d p dp dp 数组, d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 ( i , j ) (i,j) (i,j) 为右下角…

深入浅出前端本地储存

引言 2021 年,如果你的前端应用,需要在浏览器上保存数据,有三个主流方案: CookieWeb Storage (LocalStorage)IndexedDB 这些方案就是如今应用最广、浏览器兼容性最高的三种前端储存方案 今天这篇文章就聊一聊这三种方案的历史…

linux 命令笔记:gpustat

1 命令介绍 gpustat是一个基于Python的命令行工具,它提供了一种快速、简洁的方式来查看GPU的状态和使用情况它是nvidia-smi工具的一个封装,旨在以更友好和易于阅读的格式显示GPU信息。gpustat不仅显示基本的GPU状态(如温度、GPU利用率和内存…

Python爬虫获取接口数据

Python爬虫获取接口数据 正常人的操作​​​​​​​​​​爬虫的思路标题获取请求信息标题请求转换为代码完整代码请求返回信息执行程序获取静态网页数据的教程,适用于我们要爬取的数据在网页源代码中出现,但是还是有很多的数据是源代码中没有的,需要通过接口访问服务器来获…

查询优化-EXIST类型子连接提升

瀚高数据库 目录 文档用途 详细信息 文档用途 了解exist类型的子连接提升过程 详细信息 SQL: SELECT sno FROM STUDENT WHERE EXISTS (SELECT sno FROM score WHERE sno > STUDENT.sno);一、执行计划: test# explain SELECT sno FROM STUDENT WHERE EXISTS (…

代码随想录算法训练营第58天 | 392.判断子序列 , 115.不同的子序列

单调栈章节理论基础: https://leetcode.cn/problems/daily-temperatures/ 739. 每日温度 题目链接:https://leetcode.cn/problems/daily-temperatures/ 思路: 首先想到的当然是暴力解法,两层for循环,把至少需要等…

2024最新华为OD机试试题库全 -【执行时长】- C卷

1. 🌈题目详情 1.1 ⚠️题目 为了充分发挥GPU算力,需要尽可能多的将任务交给GPU执行,现在有一个任务数组,数组元素表示在这1秒内新增的任务个数且每秒都有新增任务。 假设GPU最多一次执行n个任务,一次执行耗时1秒,在保证GPU不空闲情况下,最少需要多长时间执行完成。…

Linux网络编程: TCP协议之序号和确认号详解

一、TCP协议首部 二、序号(Sequence Number) 32位,表示该报文段所发送数据的第一个字节的编号。 实际上 TCP 的序号并不是按照 “一条两条” 这样的方式来编号的。在TCP连接中所传输字节流的每一个字节都会按顺序编号,由于序列号…