【python中的多线程了解一下?】

news2024/9/21 11:03:08

在这里插入图片描述

基本说明

线程(Thread)是操作系统进行调度的最小单位,是进程中的一个独立执行单元。线程与进程相比,具有更轻量级、更高效率、更易调度、共享资源等优点。

在传统的单核CPU中,操作系统通过时间片轮转算法将CPU的时间片分配给多个线程,实现并发执行。在多核CPU的环境下,多个线程可以同时运行,提高了程序的并发性和性能。

线程可以共享进程中的内存和资源,因此可以用来实现并发编程和异步编程,提高程序的执行效率和响应速度。

在Python中,可以使用threading模块来创建和管理线程。可以通过继承Thread类或者传递一个函数对象来创建一个新线程。线程启动后,可以通过join()方法等待线程执行完成。可以使用锁、条件变量、信号量等同步机制来保证线程之间的同步和安全。

线程在Python中广泛应用于多任务并发处理、GUI编程、Web应用等场景,具有重要的作用和价值。

入门级别

1. 线程的创建

使用threading模块中的Thread类可以创建一个新的线程。创建线程时需要指定线程的目标函数,即线程要执行的代码,以及传递给目标函数的参数。

import threading

def target_function(arg1, arg2):
    # 线程要执行的代码
    pass

# 创建线程
thread = threading.Thread(target=target_function, args=(arg1, arg2))

2. 线程的启动和执行

创建线程之后,需要调用start()方法来启动线程,并开始执行线程的目标函数。

# 启动线程
thread.start()

# 等待线程执行完成
thread.join()

3. 线程的同步

线程在执行时会共享进程中的内存和资源,因此可能会出现竞争条件和并发访问问题。为了解决这些问题,Python提供了锁、条件变量、信号量等同步机制。

import threading

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

# 在代码中需要同步的位置使用锁来保证线程安全
with lock:
    # 临界区代码
    pass

中级级别

1. 线程池

线程池可以在程序启动时预先创建多个线程,然后将任务提交到线程池中执行。这样可以避免频繁创建和销毁线程,提高程序的性能。

import concurrent.futures

# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    # 提交任务到线程池中执行
    future = executor.submit(target_function, arg1, arg2)

    # 获取任务的执行结果
    result = future.result()

2. 线程间通信

线程之间需要进行通信时,可以使用共享内存、队列等方式进行数据传递。

import queue
import threading
import time

# 创建队列对象
q = queue.Queue()

# 定义生产者线程函数
def producer():
    # 生产者线程往队列中放入数据
    for i in range(10):
        data = f"生产者生产的数据:{i}"
        q.put(data)
        time.sleep(1)

# 定义消费者线程函数
def consumer():
    # 消费者线程从队列中取出数据
    while True:
        if q.qsize() > 0:
            data = q.get()
            print(f"消费者消费了数据:{data}")
            time.sleep(1)
        else:
            time.sleep(1)

# 创建生产者线程并启动
producer_thread = threading.Thread(target=producer)
producer_thread.start()

# 创建消费者线程并启动
consumer_thread = threading.Thread(target=consumer)
consumer_thread.start()

3. 线程的异常处理

线程在执行过程中可能会发生异常,需要对异常进行捕获和处理,避免程序崩溃。

import threading

def target_function():
    try:
        # 线程要执行的代码
        pass
    except Exception as e:
        # 捕获异常并进行处理
        print(f"线程执行发生异常:{e}")

# 创建线程并启动
thread = threading.Thread(target=target_function)
thread.start()

高级级别

通过condition实现生产者消费者

import threading
import time

# 缓冲区大小
BUFFER_SIZE = 10

# 生产者类
class Producer(threading.Thread):
    def __init__(self, condition, buffer):
        threading.Thread.__init__(self)
        self.condition = condition
        self.buffer = buffer

    def run(self):
        for i in range(20):
            self.condition.acquire()
            # 缓冲区已满,等待消费者消费
            while len(self.buffer) == BUFFER_SIZE:
                print('缓冲区已满,等待消费者消费')
                self.condition.wait()

            # 生产物品并添加到缓冲区
            item = 'item %s' % i
            self.buffer.append(item)
            print('生产者生产 %s' % item)

            # 通知消费者可以消费了
            self.condition.notify()
            self.condition.release()
            time.sleep(1)

# 消费者类
class Consumer(threading.Thread):
    def __init__(self, condition, buffer):
        threading.Thread.__init__(self)
        self.condition = condition
        self.buffer = buffer

    def run(self):
        for i in range(20):
            self.condition.acquire()
            # 缓冲区为空,等待生产者生产
            while len(self.buffer) == 0:
                print('缓冲区为空,等待生产者生产')
                self.condition.wait()

            # 从缓冲区取出物品并消费
            item = self.buffer.pop(0)
            print('消费者消费 %s' % item)

            # 通知生产者可以生产了
            self.condition.notify()
            self.condition.release()
            time.sleep(1)

if __name__ == '__main__':
    buffer = []
    condition = threading.Condition()
    producer = Producer(condition, buffer)
    consumer = Consumer(condition, buffer)
    producer.start()
    consumer.start()
    producer.join()
    consumer.join()

上面的代码实现了一个生产者-消费者模型,其中生产者和消费者通过共享缓冲区进行通信。代码中使用了 Python 的 threading 模块中的 Condition 对象来同步生产者和消费者线程。

在程序运行时,首先创建了一个空缓冲区和一个 Condition 对象。生产者和消费者线程分别传入这个 Condition 对象和共享的缓冲区进行初始化。然后启动生产者和消费者线程,开始生产和消费物品。生产者线程每隔 1 秒生产一个物品并将其添加到缓冲区,如果缓冲区已满则等待消费者线程消费。消费者线程每隔 1 秒从缓冲区中取出一个物品进行消费,如果缓冲区为空则等待生产者线程生产。

在生产者和消费者线程进行生产和消费操作时,都需要首先获取 Condition 对象的锁,然后通过 Condition 对象的 wait 方法进入等待状态,直到其他线程通知它们可以继续执行。当一个线程生产或消费完毕后,通过 Condition 对象的 notify 方法通知其他线程可以继续执行,然后释放 Condition 对象的锁,让其他线程进入执行状态。

通过 Condition 对象的 wait、notify 和 release 方法,可以实现线程间的同步,保证生产者和消费者线程在共享缓冲区的操作时不会互相干扰,从而避免了竞态条件和死锁等问题。

import threading
import time
# 工作线程类
class Worker(threading.Thread):
    def __init__(self, event):
        threading.Thread.__init__(self)
        self.event = event

    def run(self):
        print('工作线程 %s 等待事件' % self.name)
        self.event.wait()  # 等待事件
        print('工作线程 %s 收到事件,开始工作' % self.name)

# 主线程
if __name__ == '__main__':
    event = threading.Event()
    threads = []

    # 创建 5 个工作线程
    for i in range(5):
        t = Worker(event)
        threads.append(t)
        t.start()

    # 主线程等待 3 秒后发送事件
    print('主线程等待 3 秒后发送事件')
    for i in range(3):
        print(i+1)
        time.sleep(1)
    event.set()  # 发送事件

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

    print('所有工作线程完成')

在上面的代码中,主线程创建了一个 Event 对象,并创建了 5 个工作线程并启动它们。工作线程通过调用 Event 对象的 wait 方法进入等待状态,等待主线程发送事件。主线程等待 3 秒后发送事件,通知工作线程可以开始工作。当一个工作线程收到事件后,通过打印一条消息表示开始工作。主线程等待所有工作线程完成后,打印一条消息表示所有工作线程都已完成。

通过 Event 对象的 wait 和 set 方法,可以实现多个线程之间的同步。wait 方法用于等待事件,如果事件未发生则一直阻塞线程,直到事件被其他线程发生为止。set 方法用于发送事件,通知其他等待线程可以继续执行。多个线程可以共享同一个 Event 对象,从而实现同步。

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

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

相关文章

各种通讯总线的学习记要

一、在B站板道题看到一个比较好完视频(爱上半导体) 我觉得将232和485之前先将串口通信,因为它们都是串口通讯的变种。 串口通讯: 串口通讯我们约定好帧格式和波特率,通讯正常起始位为低开始,8位数据位&a…

【ABAQUS文档阅读笔记】关于体单元、壳单元、梁单元 、truss单元的总体认识

我的主页: 技术邻:小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩:小铭的ABAQUS学习的个人空间csdn:qgm1702 博客园文章链接: 学习笔记,from abaqus document “getting start with ABAQUS…

【代码随想录】刷题Day4

1.交换链表 24. 两两交换链表中的节点 前后指针实现 1.没有元素或者只有一个元素无意义 2.给出一个前驱prev,以及用来交换的两个节点cur和next 3.我当时是这么想的,如果两个指针一起动,那么就要用cur和next同时判断结束,也许这个…

C#基础学习--异常

目录 什么是异常 try语句 异常类 catch子句 catch子句段 finally块 为异常寻找处理程序 更进一步搜索 一般法则 抛出异常 不带异常对象的抛出 什么是异常 异常是程序运行时错误,它违反了系统约束或应用程序约束,或出现了在正常操作时未预料的情…

Windows环境下JDK内置迭代器的简介

我是荔园微风,作为一名在IT界整整25年的老兵,今天讨论一下Windows环境下JDK内置迭代器。 相信大家已经注意到,为了让广大程序员能够更加方便地操作聚合对象,在Java、C#等编程语言中都提供了内置迭代器。 如果对这种迭代器还不了…

在JetsonNano上安装PREEMPT-RT实时核+IghEtherCAT主站的详细步骤

特别说明:由于本人空闲时间有限,此博客中所有内容均是从本人的个人笔记中摘抄出来,命令行大多以图片形式展示,不能提供复制粘贴功能敬请体谅。此外,第一部分关于在 Jetson Nano 上安装PREEMPT-RT 实时核的步骤比较详细…

企业工商四要素核验 API:有效应对商业欺诈和恶意交易的利器

引言 企业工商四要素核验是一种用于验证企业基本信息的方法,主要包括企业名称、社会统一信用代码、法人名称、法人身份证四个要素。这些要素是企业注册时必须提供的信息,通过对这些信息的验证,可以确定企业的真实性和合法性,通常…

【力扣-21】合并两个有序链表

🖊作者 : Djx_hmbb 📘专栏 : 数据结构 😆今日分享 : 英文文章里 : TL;DR 或者 tl;dr。 网上英文解释有两种,一种是Too long;Don’t read,另一种是Too long;Didn’t read。意思是:“文章太长了,读…

Stable Diffusion MacBookAir 手把手安装教程,以及checkpoint安装、Lora安装、civitai介绍。

目标: 本地部署Stable Diffusion 安装步骤: 安装git Git - Downloadshttps://git-scm.com/downloads安装python 3.10.6 Python Releases for macOS | Python.orgThe official home of the Python Programming Languagehttps://www.python.org/downl…

再捐1亿元种树治沙:蚂蚁集团持续七年支持内蒙古生态治理

今天(4月22日)是“世界地球日”,内蒙古自治区林草局与蚂蚁集团启动战略合作:由蚂蚁集团在三年内再捐资1亿元,通过公益项目“蚂蚁森林”支持浑善达克沙地的生态治理。这1亿元将用于当地林草生态的修复保护、沙化土地的治…

助力电力行业数字化,BI 大有可为

各地密集上马的电力工程为上下游产业链发展带去了更多市场机遇,“三零”“三省”办电服务的推广让企业获得了看得见、摸得着的实惠,电力行业正在以自身高质量发展新成效助力经济稳增长,为扎实推进中国式现代化建设注入强劲动能。 电力行业是…

Spring Cloud Gateway Actuator API SpEL表达式注入命令执行(CVE-2022-22947)

Spring Cloud Gateway Actuator API SpEL表达式注入命令执行(CVE-2022-22947) 0x00 前言 Spring Cloud Gateway是Spring中的一个API网关。其3.1.0及3.0.6版本(包含)以前存在一处SpEL表达式注入漏洞,当攻击者可以访问…

plt.title()函数中文无法显示问题

文章目录 问题描述解决办法plt.title()函数参数说明 问题描述 由于画图时plt.title()默认是显示英文,如果我们设置标题为中文,会无法显示,如图: plt.title(训练损失) plt.plot(np.arange(len(losses)), losses, -o, colorred) p…

快速学会 IDEA 中 Git 的使用与 GitHub 仓库创建、连接、发布

🍎道阻且长,行则将至。🍓 目录 一、Git 🌴1.Git 工作流程2.Git 安装3.常用命令4.分支 二、远程仓库 GitHub 🌵1.注册使用2.配置 SSH 公钥3.在 IDEA 中配置3.IDEA to GitHub4.创建分支5.commit 到仓库6.从远程仓库中抓…

【数据结构与算法】无队头指针的队列置空队、判队空 、入队和出队算法

题目 Qestion: 假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点 (注意不设头指针) ,试编写相应的置空队、判队空、入队和出队等算法。 核心思路 该队列的特殊之处: 用链表来表示队列该链表为带头节点的链表该…

VM ware workstation安装mac虚拟机

一. 工具准备 VMware workstation mac os的镜像文件(链接:https://pan.baidu.com/s/1AdDGFU186bqKvW4wuGtpqw ,提取码:tdvc) 下载一个auto-unlocker文件(https://github.com/paolo-projects/auto-unlocke…

人工智能十大流行算法,通俗易懂讲明白

人工智能是什么?很多人都知道,但大多又都说不清楚。 事实上,人工智能已经存在于我们生活中很久了。 比如我们常常用到的邮箱,其中垃圾邮件过滤就是依靠人工智能;比如每个智能手机都配备的指纹识别或人脸识别&#x…

「QT」QT中new的对象不需要delete的原因

博客主页:何曾参静谧的博客 文章专栏:「QT」QT5快速学习 目录 说明注意事项说明 在QT中,一般来说,通过new关键字创建的对象由QT的对象树来管理,而通过其他方式创建的对象就需要手动释放。QT的对象树可以看做是QT提供的一种内存管理机制,它能够自动地管理和释放对象的内存…

Xilinx之7系列时钟规划失败解析

目录 一 、前言 二、时钟规划 ​2.1 时钟单元经过非时钟路径 2.2 资源不足 2.3 跨半区 一 、前言 在设计的工程中,经常会在implementation的布局或布线阶段失败,下面将针对xilinx 7系列时钟规划失败的场景进行分类描述。本文示例器件为xc7k480tffv1…

华为笔记本怎么录屏?分享2个实用方法

案例:如何对华为笔记本电脑进行屏幕录制? 【今天刚刚了解到电脑可以录屏,但是我拿着我的华为电脑找了半天,也找不到它的屏幕录制功能在哪。华为电脑录屏功能在哪?华为笔记本怎么录屏?有没有大神可以教教我…