使用 Python 多线程提升你的编码技能

原文:towardsdatascience.com/level-up-your-coding-skills-with-python-threading-8f1bd06b9476

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9cbfec975450d8357e227d828448ea09.png

由Sonika Agarwal在Unsplash上的照片

简介

在大多数机器学习工作中,你不会研究改进某些模型架构或设计新的损失函数。大多数时候你必须利用现有的东西并将其适应到你的用例中。因此,在架构设计和实现方面优化你的项目非常重要。一切从这里开始:你想要最优的代码,它应该是干净、可重用且尽可能快地运行。线程是 Python 内置的本地库,人们没有像应该的那样经常使用它。

关于线程

线程是程序程序将自身分割成两个或更多同时(或伪同时)运行的任务的方式……一般来说,线程包含在进程内,同一进程中的不同线程共享相同的资源。

在这篇文章中,我们不讨论多进程,但 Python 的多进程库与多线程库非常相似。一般来说:

  • 多线程非常适合 I/O 密集型任务,比如在 for 循环中调用 API

  • 多进程用于 CPU 密集型任务,比如需要一次性转换多个表格数据的任务

所以如果我们想同时运行多个任务,我们可以通过使用线程来实现。利用线程的 Python 库被称为 threading。

让我们从简单开始。我想让两个 Python 线程同时打印一些东西。让我们编写两个包含 for 循环以打印一些单词的函数。

defprint_hello():forxinrange(1_000):print("hello")defprint_world():forxinrange(1_000):print("world")

现在如果我是依次运行,我会在我的终端中看到 1.000 次“hello”后面跟着 1.000 次“world”。

让我们使用线程。让我们定义两个线程,并将每个线程分配给上面定义的函数。然后我们将启动线程。你应该会在你的终端上看到“hello”和“world”交替打印。

如果在继续执行你的代码之前你想等待线程完成,你可以通过使用:join()来实现。

importthreding thread_1=threding.Thread(target=print_hello)thread_2=threding.Thread(target=print_world)thread_1.start()thread_2.start()# wait for the threads to finish before continuing running the codethread_1.join()thread_2.join()print("do other stuff")

使用线程锁定资源

有时候可能会发生两个或更多线程编辑相同的资源,比如说一个包含数字的变量。

一个线程有一个总是将 1 加到该变量的 for 循环,另一个线程减 1。如果我们同时运行这些线程,它将“始终”具有零(或多或少)的值。但我们要实现不同的行为。第一个获得这个变量的线程需要添加或减去 1,直到达到某个限制。然后它将释放变量,另一个线程就可以自由地获得变量并执行其操作。

importthreadingimporttime x=0lock=threading.Lock()defadd_one():globalx,lock# use global to work with globa varslock.acquire()whilex<10:x=x+1print(x)time.sleep(1)print("reached maximum")lock.release()defsubtract_one():globalx,lock lock.acquire()while>-10:x=x-1print(x)time.sleep(1)print("reached minimum")lock.release()

在上面的代码中,我们有两个函数。每个函数将由一个线程运行。一旦函数开始,它将锁定变量 lock,这样第二个线程在第一个线程完成之前无法访问它。

thread_1=threading.Thread(target=add_one)thread_2=threading.Thread(target=subtract_one)thread_1.start()thread_2.start()

使用信号量加锁

我们可以通过使用信号量来实现与上面类似的结果。假设我们想要一个函数同时被一定数量的线程访问。这意味着不是所有线程都能访问这个函数,例如只有 5 个线程。其他线程需要等待这 5 个线程中的某些完成它们的计算才能访问该函数并运行脚本。我们可以通过使用信号量和将其值设置为 5 来实现这一点。要使用某些参数启动一个线程,我们可以在 Thread 对象中使用args

importtimeimportthreading semaphore=threading.BoudnedSemaphore(value=5)deffunc(thread_number):print(f"{thread_number}is trying to access the resource")semaphore.acquire()print(f"{thread_number}granted access to the resource")time.sleep(12)#fake some computationprint(f"{thread_number}is releasing resource")semaphore.release()if__name__=="__main__":forthread_numberinrange(10):t=threading.Thread(target=func,args=(thread_number,)t.start()time.sleep(1)

事件

事件****是简单的信号机制,用于协调线程。你可以把事件想象成一个你可以设置或清除的标志,其他线程可以在它被设置之前等待,然后继续它们的工作。

例如,在下面的例子中,想要执行“func”函数的 thread_1 需要等待用户输入“yes”并触发事件,才能完成整个函数。

importthreading event=threading.Event()deffunc():print("This event function is waiting to be triggered")event.wait()print("event is triggered, performing action now")thread_1=threading.Thread(target=func)thread_1.start()x=input("Do you want to trigger the event? n")ifx=="yes":event.set()elseprint("you chose not to trigger the event")

守护线程

这些只是运行在后台的线程。即使这个后台线程仍在运行,主脚本也会终止。例如,你可以使用守护线程来持续读取一个随时间更新的文件。

让我们编写一个脚本,其中有一个守护线程持续从文件中读取并更新一个字符串变量,另一个线程将变量的内容打印到控制台。

importthreadingimporttime path="myfile.txt"text=""defread_from_file():globalpath,textwhileTrue:withopen(path,"r")asf:text=f.read()time.sleep(4)defprint_loop():forxinrange(30):print(text)time.sleep(1)thread_1=threading.Thread(target=read_from_file,daemon=True)thread_2=threading.Thread(target=print_loop)thread_1.start()thread_2.start()

队列

队列是一组遵循先进先出(FIFO)原则的项目集合。它是一种处理数据结构的方法,其中首先处理第一个元素,最后处理最新元素。

我们还可以更改我们处理集合中项目顺序的优先级。例如,LIFO 代表后进先出。或者,我们可以有一个优先队列,我们可以手动选择顺序。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/44c3dfac64561c0dd50f0a645cfb8372.png

src:miro.medium.com/v2/resize:fit:1280/0*HUWegihFk4x2x5vS.gif

如果多个线程想要处理一个项目列表,比如数字列表,可能会出现两个线程对同一项进行计算的问题。我们想要避免这种情况。因此,我们可以在线程之间共享一个队列,当一个线程对其项目进行计算时,该项目将从队列中移除。让我们看看一个例子。

importqueue q=queue.Queue()# it can also be a LifoQueue or PriorityQueuenumber_list=[10,20,30,40,50,60,70,80]fornumberinnumber_list:q.put(number)print(q.get())# -> 10print(1.het())# -> 20

机器学习项目中线程的例子

假设你正在做一个项目,需要数据流和预处理管道。这在许多项目中都会发生,比如物联网设备或任何类型的传感器。后台守护线程可以持续获取和预处理数据,而主线程则专注于推理。

例如,在一个简单的案例中,我需要使用我的相机流开发一个实时图像分类系统。我会设置我的线程,拥有 2 个线程:

  • 实时从相机流中获取图像。

  • 将图像传递给机器学习模型进行推理。

importthreadingimporttimeimportqueueimportrandom# Sfake image classifierdefclassify_image(image):time.sleep(0.5)# fake the model inference timereturnf"Classified{image}"defcamera_feed(image_queue,stop_event):whilenotstop_event.is_set():# Simulate capturing an imageimage=f"Image_{random.randint(1,100)}"print(f"[Camera] Captured{image}")image_queue.put(image)time.sleep(1)# Simulate time between capturesdefmain_inference_loop(image_queue,stop_event):whilenotstop_event.is_set()ornotimage_queue.empty():try:image=image_queue.get(timeout=1)# Fetch image from the queueresult=classify_image(image)print(f"[Model]{result}")exceptqueue.Empty:continueif__name__=="__main__":image_queue=queue.Queue()stop_event=threading.Event()camera_thread=threading.Thread(target=camera_feed,args=(image_queue,stop_event),daemon=True)camera_thread.start()try:main_inference_loop(image_queue,stop_event)exceptKeyboardInterrupt:print("Shutting down...")stop_event.set()# Signal the camera thread to stopfinally:camera_thread.join()# Ensure the camera thread terminates properlyprint("All threads terminated.")

在这个简单的例子中,我们有:

  • 守护线程:相机输入在后台运行,所以当主线程完成时,它不会阻止程序退出。

  • 协调事件:这个stop_event允许主线程向守护线程发送终止信号。

  • 通信队列:这个image_queue确保线程之间安全、线程安全的通信。

最后的想法

在这个教程中,我展示了如何使用 Python 的线程库,涵盖了基础概念,如锁、信号量和事件,以及更高级的使用案例,如守护线程和队列。

我想强调,线程化不仅仅是一种技术技能,它更像是一种心态,使你能够编写干净、高效和可重用的代码。无论你是在管理 API 调用、处理传感器数据流,还是在构建实时 AI 应用,线程化都允许你构建健壮、响应迅速且易于扩展的系统。

如果你喜欢这篇文章,请关注我的Medium!😁

💼 领英 ️| 🐦 X (Twitter) | 💻 网站

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

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

相关文章

ESP32连接阿里云MQTT:网络协议栈配置实战案例

ESP32连接阿里云MQTT实战&#xff1a;从协议栈配置到稳定上线的完整路径 你有没有遇到过这样的场景&#xff1f; ESP32明明连上了Wi-Fi&#xff0c;IP也拿到了&#xff0c;可就是连不上阿里云&#xff1b;日志里反复打印“TLS handshake failed”或“Connection timeout”&am…

[特殊字符]_网络IO性能优化:从TCP到HTTP的层层优化[20260106161818]

作为一名专注于网络性能优化的工程师&#xff0c;我在过去的项目中积累了丰富的网络IO优化经验。最近&#xff0c;我参与了一个对网络性能要求极高的项目——实时视频流平台。这个项目让我重新审视了Web框架在网络IO方面的表现。今天我要分享的是基于真实项目经验的网络IO性能优…

利用 KeyBERT、HDBSCAN 和 Zephyr-7B-Beta 构建知识图谱

原文&#xff1a;towardsdatascience.com/leverage-keybert-hdbscan-and-zephyr-7b-beta-to-build-a-knowledge-graph-33d7534ee01b?sourcecollection_archive---------0-----------------------#2024-01-07 增强型大语言模型自然语言处理与传统机器学习技术结合&#xff0c;用…

SAPlink终极指南:5个技巧掌握ABAP对象高效管理

SAPlink终极指南&#xff1a;5个技巧掌握ABAP对象高效管理 【免费下载链接】SAPlink SAPlink 项目地址: https://gitcode.com/gh_mirrors/sa/SAPlink SAPlink是一款专为SAP Netweaver系统设计的ABAP对象导入导出工具&#xff0c;通过独特的Nugget文件格式实现了代码的便…

ms-swift支持训练任务超时自动终止释放资源

ms-swift支持训练任务超时自动终止释放资源 在大模型时代&#xff0c;一个看似微不足道的“卡住”任务&#xff0c;可能意味着数小时GPU算力的浪费、数千元云成本的流失&#xff0c;甚至影响整个团队的迭代节奏。你有没有经历过这样的场景&#xff1a;提交了一个LoRA微调任务&…

得意黑 Smiley Sans 字体安装与应用全攻略:从下载到专业设计的完美指南

得意黑 Smiley Sans 字体安装与应用全攻略&#xff1a;从下载到专业设计的完美指南 【免费下载链接】smiley-sans 得意黑 Smiley Sans&#xff1a;一款在人文观感和几何特征中寻找平衡的中文黑体 项目地址: https://gitcode.com/gh_mirrors/smi/smiley-sans 还在为字体安…

STNodeEditor实战指南:构建高效可视化编程工作流

STNodeEditor实战指南&#xff1a;构建高效可视化编程工作流 【免费下载链接】STNodeEditor 一款基于.Net WinForm的节点编辑器 纯GDI绘制 使用方式非常简洁 提供了丰富的属性以及事件 可以非常方便的完成节点之间数据的交互及通知 大量的虚函数供开发者重写具有很高的自由性 …

盲水印终极使用指南:保护图像版权的完整解决方案

盲水印终极使用指南&#xff1a;保护图像版权的完整解决方案 【免费下载链接】BlindWaterMark 盲水印 by python 项目地址: https://gitcode.com/gh_mirrors/bli/BlindWaterMark 盲水印技术是现代数字版权保护的重要工具&#xff0c;它能在不改变图像视觉质量的前提下&a…

常见网络安全威胁和防御措施

网络安全威胁是一种技术风险&#xff0c;会削弱企业网络的防御能力&#xff0c;危及专有数据、关键应用程序和整个 IT 基础设施。由于企业面临广泛的威胁&#xff0c;因此他们应该仔细监控和缓解最关键的威胁和漏洞。网络安全问题有七大类&#xff0c;它们都包括多种威胁&#…

ncmdumpGUI终极指南:网易云音乐NCM格式转换完整解决方案

ncmdumpGUI终极指南&#xff1a;网易云音乐NCM格式转换完整解决方案 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 在音乐数字化时代&#xff0c;网易云音乐的…

终极SAP开发利器:SAPlink高效代码迁移完全指南

终极SAP开发利器&#xff1a;SAPlink高效代码迁移完全指南 【免费下载链接】SAPlink SAPlink 项目地址: https://gitcode.com/gh_mirrors/sa/SAPlink 在传统的SAP Netweaver开发环境中&#xff0c;ABAP程序员常常面临一个痛点&#xff1a;如何在不同系统间安全、高效地迁…

视频字幕制作效率革命:AI智能助手如何10倍提升创作生产力

视频字幕制作效率革命&#xff1a;AI智能助手如何10倍提升创作生产力 【免费下载链接】VideoCaptioner &#x1f3ac; 卡卡字幕助手 | VideoCaptioner - 基于 LLM 的智能字幕助手&#xff0c;无需GPU一键高质量字幕视频合成&#xff01;视频字幕生成、断句、校正、字幕翻译全流…

强力解锁ArchiMate企业架构建模:3步安装与5大核心功能深度解析

强力解锁ArchiMate企业架构建模&#xff1a;3步安装与5大核心功能深度解析 【免费下载链接】archi Archi: ArchiMate Modelling Tool 项目地址: https://gitcode.com/gh_mirrors/arc/archi 你是否正在寻找一款功能强大且完全免费的ArchiMate建模工具&#xff1f;Archi正…

解决WPS中Zotero插件双图标冲突的实用指南

解决WPS中Zotero插件双图标冲突的实用指南 【免费下载链接】WPS-Zotero An add-on for WPS Writer to integrate with Zotero. 项目地址: https://gitcode.com/gh_mirrors/wp/WPS-Zotero 当你在WPS Office中同时看到两个Zotero插件图标&#xff0c;其中一个无法正常使用…

KLayout终极指南:从入门到精通的完整版图设计解决方案

KLayout终极指南&#xff1a;从入门到精通的完整版图设计解决方案 【免费下载链接】klayout KLayout Main Sources 项目地址: https://gitcode.com/gh_mirrors/kl/klayout KLayout作为一款专业的集成电路版图设计工具&#xff0c;以其轻量级架构和全功能覆盖在EDA领域占…

ms-swift支持训练资源使用率报表生成

ms-swift支持训练资源使用率报表生成 在当前大模型训练日益成为AI研发核心环节的背景下&#xff0c;一个现实问题正困扰着无数开发者&#xff1a;我们花了几万甚至几十万元租用A100/H100集群跑一次微调任务&#xff0c;结果发现GPU利用率长期徘徊在30%以下——算力明明买了&…

Steam成就管理终极指南:7步轻松掌握SteamAchievementManager

Steam成就管理终极指南&#xff1a;7步轻松掌握SteamAchievementManager 【免费下载链接】SteamAchievementManager A manager for game achievements in Steam. 项目地址: https://gitcode.com/gh_mirrors/st/SteamAchievementManager 还在为某些难以达成的Steam成就而…

EverythingToolbar:重新定义Windows任务栏搜索体验

EverythingToolbar&#xff1a;重新定义Windows任务栏搜索体验 【免费下载链接】EverythingToolbar Everything integration for the Windows taskbar. 项目地址: https://gitcode.com/gh_mirrors/eve/EverythingToolbar 在数字工作环境中&#xff0c;文件检索效率直接影…

KLayout专业版图设计:从入门到精通的完整解决方案

KLayout专业版图设计&#xff1a;从入门到精通的完整解决方案 【免费下载链接】klayout KLayout Main Sources 项目地址: https://gitcode.com/gh_mirrors/kl/klayout 在当今快速发展的半导体行业&#xff0c;选择一款合适的EDA工具对版图设计工程师来说至关重要。KLayo…

STNodeEditor终极指南:零基础掌握C可视化编程工具

STNodeEditor终极指南&#xff1a;零基础掌握C#可视化编程工具 【免费下载链接】STNodeEditor 一款基于.Net WinForm的节点编辑器 纯GDI绘制 使用方式非常简洁 提供了丰富的属性以及事件 可以非常方便的完成节点之间数据的交互及通知 大量的虚函数供开发者重写具有很高的自由性…