python 自定义多线程的传参方式是什么

news2024/12/27 18:57:00

在 Python 中,threading 模块提供了多线程编程的支持,允许我们通过创建线程类的方式来实现并发操作。当我们自定义线程类时,可以通过修改类的构造方法和运行逻辑来传递和处理参数。

以下面这个实际的代码片段为例来说明:

import threading

class MyThread(threading.Thread):

    def run(self):
        print(self._args)

t = MyThread(args=(100,))
t.start()

从这段代码来看,MyThread 继承自 threading.Thread,并且只重写了 run() 方法。在这里的 run() 方法中,它试图输出 self._args。根据一般的编程经验,_args 并不是一个标准的属性名,而是一个在代码中没有显式定义的属性。因此,我们需要理解,这里的 self._args 是如何出现的,以及传参的逻辑是如何工作的。

分析 Python 自定义多线程传参的机制

继承自 threading.Thread

threading.Thread 是 Python 标准库中的一个类,支持线程创建与管理。当你从 threading.Thread 派生子类时,系统提供了两种方式来为线程传递参数:

  1. 通过重写 __init__ 方法
  2. 通过 Thread 类的 argskwargs 参数

上面代码中,并没有重写 __init__ 方法,使用的是 threading.Thread 提供的默认构造器。threading.Thread 类的 __init__ 方法接受两个特别重要的参数:argskwargs,这两个参数分别用于传递位置参数和关键字参数。这是标准的 Python 多线程类的传参方式。

我们可以查看 threading.Thread 类的源码来验证这一点。threading.Thread__init__ 方法是这样定义的:

class Thread:
    def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, daemon=None):
        ...
        self._args = args
        self._kwargs = kwargs
        ...

_args 参数

从源码可以看出,__init__ 方法接收了 argskwargs 参数,并且将它们赋值给了 self._argsself._kwargs。也就是说,在创建线程对象时,我们可以通过 args 参数向线程传递位置参数,而这些参数会自动存储在 self._args 中。这解释了你在 run 方法中直接访问 self._args 的原因。

传参的具体实现

当你创建 MyThread 实例时,像这样:

t = MyThread(args=(100,))

你实际上调用了 threading.Thread 的默认构造函数,而 args=(100,) 被传递给了这个构造函数。在构造函数内部,args 被赋值给了 self._args,这就是为什么你可以在 run() 方法中访问 self._args 的原因。

运行这个线程时,run() 方法被调用,线程会输出 self._args 中的内容,也就是 (100,)

修改代码以更清晰地控制传参

虽然你没有重写 __init__ 方法,但如果你希望显式控制传参,并且想让代码更具可读性,可以通过重写 __init__ 方法来实现。这可以让你更清楚地看到参数传递的过程。你可以这样改写代码:

import threading

class MyThread(threading.Thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.my_args = args

    def run(self):
        print(self.my_args)

t = MyThread(100)
t.start()

在这个版本中,我们重写了 __init__ 方法,并通过 super().__init__(*args, **kwargs) 调用父类的构造函数。这允许我们继续使用 threading.Thread 的内置功能。同时,我们将参数保存在 self.my_args 中,以便在 run() 方法中访问。

通过这种方式,我们明确地控制了参数的传递,并避免了依赖 threading.Thread 类的隐式行为。这样代码的结构更加清晰,也让维护和扩展变得更简单。

Python 多线程的其他传参方式

除了通过 argskwargs 传递参数,还有其他常见的方式来为自定义线程传递参数。一个常见的方法是将参数封装在对象内部,或者通过队列等线程安全的数据结构来传递参数和结果。下面是几种典型的做法:

1. 直接通过构造函数传递参数

如上面提到的例子,重写 __init__ 方法,并通过构造函数传递参数。这样可以确保参数在对象创建时被正确传递并存储。

2. 使用队列进行线程间通信

queue.Queue 是一个线程安全的队列,可以用于在线程之间传递参数和结果。这种方式适用于复杂的多线程应用,尤其是在需要多个线程共享数据时。

import threading
import queue

def worker(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(f'Processing {item}')
        q.task_done()

q = queue.Queue()
thread = threading.Thread(target=worker, args=(q,))
thread.start()

# 传递参数
for item in range(5):
    q.put(item)

q.put(None)  # 通知线程退出
thread.join()

在这个例子中,队列 q 被用来传递参数给线程。线程可以从队列中提取任务进行处理。这样既保证了线程的同步,也避免了参数直接传递的复杂性。

3. 使用线程本地数据

threading.local() 提供了一种在多线程环境中管理局部数据的方法。每个线程都有自己的本地存储空间,可以用于存储特定的参数和数据。

import threading

thread_local = threading.local()

def worker():
    print(f'Hello, {thread_local.name}')

def set_name(name):
    thread_local.name = name
    worker()

thread1 = threading.Thread(target=set_name, args=('Alice',))
thread2 = threading.Thread(target=set_name, args=('Bob',))

thread1.start()
thread2.start()

thread1.join()
thread2.join()

在这个例子中,threading.local() 创建了一个线程本地的存储空间。每个线程可以独立地访问和修改 thread_local 中的数据,而不会影响其他线程。通过这种方式,可以实现线程独立的参数传递。

自定义多线程传参的最佳实践

在自定义线程时,选择适当的传参方式对于代码的可维护性和健壮性非常重要。这里有一些建议可以帮助你选择合适的方法:

  • 参数简单时,使用 argskwargs 来传递参数是最直接的方式。它利用了 threading.Thread 的内置功能,减少了代码的复杂性。
  • 当需要线程间通信时,使用队列或其他同步原语(如 EventSemaphore 等)是一个更好的选择。队列可以保证线程安全地传递数据,避免了资源竞争问题。
  • 需要局部线程数据时threading.local() 提供了一种轻量级的方式来管理每个线程的独立数据。它非常适合处理线程特定的配置或状态。

线程安全问题与参数传递的影响

多线程编程中的一个核心问题是线程安全。虽然传递参数是线程执行的必要部分,但如何确保线程安全地访问和处理这些参数同样重要。某些情况下,多个线程可能需要访问共享的数据或资源,而错误地访问这些资源可能导致竞态条件和不一致的结果。

在处理参数传递时,需要特别注意:

  • 数据的共享与保护:如果多个线程共享同一组数据(如全局变量、列表等),则需要使用锁(Lock)或条件变量(Condition)来保护这些数据。
  • 不可变数据:当参数是不可变的数据类型(如元组、字符串等)时,传递这些参数通常是安全的,因为不可变对象在 Python 中是线程安全的。
  • 深拷贝与浅拷贝:当传递可变对象时,特别是列表、字典等容器时,需要考虑是否应该使用拷贝操作来避免不同线程对同一数据进行修改。

下面是一个例子,展示如何使用 Lock 来确保线程安全地访问共享资源:

import threading

lock = threading.Lock()
shared_resource = []

def worker(item):
    with lock:
        shared_resource.append(item)
        print(f'Item {item} added.')

threads = []
for i in range(5):
    t = threading.Thread(target=worker, args=(i,))
    t.start()
    threads.append(t)

for t in threads:


    t.join()

print(f'Final shared resource: {shared_resource}')

在这个例子中,多个线程需要访问 shared_resource,这是一个共享的列表。使用 Lock 确保每个线程在访问和修改 shared_resource 时不会发生竞态条件。

结论

自定义多线程的传参方式在 Python 中有多种实现方式,最常见的就是通过 argskwargs 参数传递。同时,也可以使用更复杂的技术,如队列、线程本地数据和锁,来满足多线程应用中的参数传递和线程安全需求。

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

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

相关文章

BootROM清除密码

目录 一、组网需求 二、操作步骤 1. console连接设备 2.重启设备 3. 进入BootROM菜单 a. 选择第4项,进入Startup Select菜单 查看系统使用的配置信息 重命名系统使用的配置文件 启动设备 停止Auto-Config 将重命名的配置文件改为可执行文件 恢复配置 重…

迈巴赫 S480 的奢华升级之旅头等舱行政独立 4 座

《迈巴赫 S480 的奢华升级之旅:头等舱行政独立 4 座》 迈巴赫 S480,作为豪华轿车的典范,一直以来都以其卓越的品质和尊贵的体验而备受推崇。而对于那些追求极致奢华与舒适的车主来说,将其升级为头等舱行政独立 4 座的配置&#x…

使用WebClient 快速发起请求(不使用WebClientUtils工具类)

使用WebClient发起网络请求_webclient工具类-CSDN博客文章浏览阅读717次,点赞9次,收藏8次。使用WebClient发起网络请求_webclient工具类https://blog.csdn.net/qq_43544074/article/details/137044825这个是使用工具类发起的,下面就不使用工具…

Chrome浏览器的C++内存管理技术揭秘

Chrome浏览器作为全球最流行的网络浏览器之一,其高效的内存管理技术功不可没。本文将深入探讨Chrome浏览器在C中的内存管理技术,并介绍如何通过调整网页加载时间、优化视频播放体验和解决谷歌浏览器占用CPU过高的问题来提升浏览器性能。 (本…

生产绩效考核管理的六大指标

生产绩效考核管理的六大指标 绩效考核是指生产部所有人员通过不断丰富自己的知识、提高自己的技能、改善自己的工作态度,努力创造良好的工作环境及工作机会,不断提高生产效率、提高产品质量、提高员工士气、降低成本以及保证交期和安全生产的结果和行为…

E35.【C语言】判断大/小端序

1.题目 写一个程序实现大/小端序的判断 2.前置知识 见文61.【C语言】数据在内存中的存储 见文65.【C语言】联合体 3.代码 方案一 对于单个变量,判断存储的第一个字节 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() {int a 2;if ((*(char*)&…

七星创客:重塑商业模式认知

近期&#xff0c;一个普遍存在的疑问困扰着许多人&#xff1a;“商业模式是否仅仅等同于拉人头或传销活动&#xff1f;”这样的联想或许源于对商业模式概念的片面理解&#xff0c;使得一些人错误地将所有商业模式都笼罩在负面阴影之下。 商业模式&#xff0c;这一商业领域的核心…

两千价位段最亮的激光投影仪?当贝D6X高亮版卷出新高度

当贝D6X系列作为当贝投影上半年发布的重磅新品&#xff0c;其最大的亮点就是采用了AI双屏设计&#xff0c;首创的AI“灵动屏”&#xff0c;不仅颜值吸睛&#xff0c;而且功能多样&#xff0c;一经发布就引发热议。其中&#xff0c;采用三色激光的当贝D6X&#xff0c;因其出色的…

荣耀问鼎!宏山激光斩获2024年度行业创新大奖

8月28日&#xff0c;由高科技行业门户OFweek维科网主办的“维科杯OFweek2024激光行业年度评选”于中国深圳成功举办。宏山激光凭借出类拔萃的技术创新实力与卓越品质&#xff0c;成功斩获“维科杯OFweek2024年度激光行业最佳智能装备/自动化产线技术创新奖”。 这一殊荣绝非偶然…

流水线并行(Pipeline Parallelism)原理详解

文章目录 0. 概览1. 简单流水并行2. GPipe 算法3. GPipe 空间复杂度4. PipeDream 算法5. 总结参考 0. 概览 数据并行&#xff08;Data Parallelism&#xff09;&#xff1a;在不同的GPU上运行同一批数据的不同子集&#xff1b; 流水并行&#xff08;Pipeline Parallelism&…

QCamera6.7笔记

1.QCamera​ .h文件 #include <QtWidgets/QMainWindow> #include "ui_QCamera_test1.h" #include <QCamera> #include <QtMultimedia> #include <QtMultimediaWidgets> #include<QMediaCaptureSession> #include <QMediaDevices&…

基于微信小程序的美食推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

KEYSIGHT N993xA 手持频谱分析仪(SA)

N993xA 手持频谱分析仪(SA) 苏州新利通 N993xA 手持频谱分析仪(SA) FieldFox 手持式射频和微波分析仪 Keysight FieldFox 便携式分析仪可以在非常恶劣的工作环境中&#xff0c;轻松完成从日常维护到深入故障诊断的各项工作。 选择最适合您需求且有强大软件支持的 Keysight …

vector中push_back和emplace_back的区别

push_back 在引入右值引用&#xff0c;转移构造函数&#xff0c;转移复制运算符之前&#xff0c;通常使用push_back()向容器中加入一个右值元素&#xff08;临时对象&#xff09;的时候&#xff0c;首先会调用构造函数构造这个临时对象&#xff0c;然后需要调用拷贝构造函数将…

Java项目实战II基于Java+Spring Boot+MySQL的免税商品优选购物商城(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着全球贸易的日益繁荣和消费者需求的多样化&#xff0c;免税商品购物已成为众多旅行者和消费者的热…

【C++】set详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

对异步处理的http接口进行性能测试

最近来了新的领导&#xff0c;测试的内容和范畴都变大了&#xff0c;工作内容涉及到APP&#xff0c;线上出现了由于性能引起的bug&#xff0c;不得不进行压测&#xff0c;只能不断的学习了。害&#xff0c;想做一条咸鱼都那么难&#xff0c;找了很多关于接口性能测试的资料&…

模板初阶、auto关键字、范围for和string类的使用

目录 1. 模板初阶 1.1 泛型编程 1.2 函数模板 1.3 类模板 2. auto关键字 3. 范围for的使用&#xff08;略提&#xff09; 4. String类部分接口的使用 4.1 String构造函数的使用 4.2 string类begin和end的使用 4.3 string类的rbegin和rend的使用 4.4 string类的size和length的使…

使用 npkill 快速清理本地 node_modules 文件

npkill 可以直接在终端可视化的清除 本地 node_modules 文件夹&#xff0c;方便我们即使清除不常用的依赖。 直接在终端执行 npx npkill 即可开启 node_modules 本地扫描&#xff1a; 然后&#xff0c;我们选择不需要的 node_modules 按下空格即可删除。

sentinel2 L2A处理基线04.00 反射率计算方法

sentinel2 处理基线04.00发布后&#xff0c;L2A地表反射率计算方式也发生了调整&#xff1b;根据新版的数据说明&#xff0c;新版数据增加了负值偏移。因此计算时需要读取数据产品中MTD_MSIL2A.xml的元文件。注意&#xff0c;相比之前的版本&#xff0c;元文件中增加了BOA_ADD_…