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

在这里插入图片描述

基本说明

线程(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.mfbz.cn/a/13167.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里版 ChatGPT 突然上线!

转自:纯洁的微笑 其实早本月初,就传出过不少阿里要推出类ChatGPT的消息。 前几天率先流出的天猫精灵“鸟鸟分鸟”脱口秀版GPT,就是基于大模型的“压缩版”,已经以其惊艳表现吸引了众目光。 如今“原版大菜”上桌,自然一点即着&a…

实验设备管理系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设!!! 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址:https://download.csdn.net/download/qq_50954361/87682549 更多系统资源库…

用梯度下降的方式来拟合曲线

文章目录 1. 简述2. 理论原理以二次函数为例整体的梯度下降步骤: 3. 编码实现初始化权重矩阵计算损失和梯度更新权重 4. 结果首先对上一篇文章中的真实数据拟合。测试拟合高次曲线方程数据是2阶的,拟合方程是2阶的数据是4阶的,拟合方程也是4阶…

可配置物料-文章资料分享

可配置物料项目一般很少用到,用到就是要命,推荐一下之前查资料收集的资料,分享给大家。感谢这位大佬收集的文章! Variant Configuration (LO-VC) - Product Lifecycle Management - Support Wikihttps://archive.sap.com/document…

研报精选230419

目录 【行业230419东吴证券】AACR2023本土药企临床进展:“秒懂”全球创新药系列研究之会议追踪 【行业230419浙商证券】大制造行业估值手册:周度数据跟踪 【行业230419东方财富证券】2023上海车展前瞻:自主争先,迎接智能电动新时代…

Linux网络服务之DHCP篇

目录 一、了解DHCP服务1.1DHCP定义1.2DHCP好处1.3DHCP的分配方式 二、DHCP工作过程三. 使用DHCP动态配置主机地址 一、了解DHCP服务 1.1DHCP定义 DHCP(动态主机配置协议)是一个局域网的网络协议。指的是由服务器控制一段IP地址范围,客户机登…

【Mysql】分库分表

【Mysql】分库分表 文章目录 【Mysql】分库分表1. 介绍2. 拆分策略2.1 垂直拆分2.1.1 垂直分库2.1.2 垂直分表 2.2 水平拆分2.2.1 水平分库2.2.2 水平分表 3. MyCat3.1 概述 1. 介绍 采用单数据库进行数据存储存在以下瓶颈: IO瓶颈:热点数据太多&#x…

java IO流_1

目录 分类 字节流 InputStream OutputStream 文件拷贝 字符流 FileReader FileWriter 处理流 BufferedReader BufferedWriter 文本拷贝 流是从起源到接受的有序数据,通过流的方式允许程序使用相同的方式来访问不同的输入/输出源。 分类 按数据…

4.26和4.27、selectAPI介绍(4.27、select代码)

4.26和4.27、selectAPI介绍(4.27、select代码) 1.selectAPI介绍①select多路复用流程图②select多路复用缺点 2.select代码使用介绍3.select代码实现①select服务端实现②select客户端实现 1.selectAPI介绍 主旨思想: 首先要构造一个关于文件…

echarts中横坐标显示为time,使用手册

需求: 后端传递(两段数据,不同时间间隔)的24h实时数据,前端需要根据24小时时间展示,要求:x轴为0-24h,每个两小时一个刻度 误区: 刚开始通过二维数据的形式秒点&#xff…

MySQL数据库从入门到精通学习第2天(创建数据库)

创建数据库 通过CREATE DATABASE语句来创建数据库通过CREATE SCHEMA语句来创建数据库通过IF NOT EXISTS进行判断创建 通过CREATE DATABASE语句来创建数据库 创建数据库的语法格式如下: CREATE DATABASE 【数据库名】; 创建数据库的库名跟标识符一样也是有要求的&…

设计模式-结构型模式之桥接模式

2. 桥接模式 2.1. 模式动机 设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案: 第一种设计方案是为每一种形状…

android sdl编译

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台。 1 下载SDL源码 http://www.libsd…

这篇把「精准测试」算是讲明白了

作为测试同学,我们经常在工作中会有这样的困惑:我写的用例真的有效且全面吗,我的测试真的做到有效覆盖了吗?回归阶段我到底需要回归什么,回归验证充分吗?这次的改动到底影响范围有多大?针对以上…

从编译器角度理解C++编译和连接原理

C编译链接整体介绍 链接主要工作 1 所有.o文件段的合并,符号表合并后,进行符号解析 链接时就是在符号表中找对应的符号是否只出现于.text或.data段一次,若一次都无,则符号未定义;若出现多次,符号重定义 符…

学习风`宇博客用户权限菜单模块

文章目录 用户-角色-菜单-资源 各表关系图菜单 和 路由菜单表及分析分析 /api/admin/user/menus接口MenuServiceImpl#listUserMenus接口返回示例及分析 前端代码分析menu.jsSideBar.vue 接口权限控制资源表 及 分析分析 WebSecurityConfig权限控制整体流程先说登录UserDetailsS…

行业那么多,为什么计算机领域这么火?

行业那么多,为什么计算机领域这么火? 计算机领域火已经不是一天两天了,从开始的进入互联网时代、到“互联网”、再到大数据、人工智能时代、数字化经济……计算机技术从行业内部的自我发展逐渐渗透到各行各业,甚至成为社会整体经济…

JVM-GC回收机制

目录 1.判定垃圾 1.引用计数 2.可达性分析 2.清理垃圾 1.标记清除 2.复制算法 3.标记整理 4.分代回收 上文讲述的Java运行时内存划分,对于程序计数器,虚拟机栈,本地方法栈来说,生命周期是和线程有关的,随着线程而生,随线程而灭,当方法结束或者线程结束时,它们的内存就自…

【Python_Scrapy学习笔记(十)】基于Scrapy框架的下载器中间件创建代理IP池

基于Scrapy框架的下载器中间件创建代理IP池 前言 本文中介绍 如何基于 Scrapy 框架的下载器中间件创建代理IP池。 正文 1、添加中间件的流程 在 middlewares.py 中新建 代理IP 中间件类在 settings.py 中添加此下载器中间件,设置优先级并开启 2、基于Scrapy框…

软件安全之CRC检测

CRC介绍 在玩某些游戏,例如fps类游戏时,你想要修改某些特定的数值实现一些功能,这时你很有可能会被查封账号甚至禁封机器码。因为你更改了游戏中的数据,从而导致接收方收到”错误的数据“。为尽量提高接收方收到数据的正确率&…
最新文章