【Python】线程和多线程的使用

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。


文章目录

  • 前言
  • 一、基本概念
  • 二、python线程
    • 1.函数调用
    • 2.类的调用
  • 三、共享全局变量
  • 四、守护线程
  • 五、线程锁
  • 六、杀死进程


前言


一、基本概念

线程是计算机中的基本执行单元。一个进程中可以拥有多个线程,这些线程可以并发地执行不同的任务。线程共享进程的资源,包括内存空间、文件和其他系统资源。通过使用多线程,程序可以在同一时间执行多个任务,提高系统的并发性和响应性。

线程可以分为用户线程和内核线程。用户线程是由应用程序开发者创建和管理的,它们只在用户空间内运行,不需要内核的支持。而内核线程是由操作系统内核创建和管理的,它们在内核空间内运行,并通过系统调用来与操作系统进行交互。

线程的创建和销毁是轻量级的操作,相比于进程的创建和销毁,更加高效。线程可以共享进程的地址空间,因此可以直接访问进程的全局变量和数据结构。但是,由于多个线程共享同一片内存空间,需要进行同步和互斥来保证数据的一致性和可靠性。

线程可以实现并行和并发的效果,使得程序可以同时执行多个任务。并行是指多个任务在同一时刻同时执行,而并发是指多个任务交替执行,通过时间片轮转使得多个任务共享CPU的时间。通过合理地使用线程,可以提高程序的性能和效率。

二、python线程

Python中的线程是基于线程切换的,并不是真正的并行执行。这是因为Python中的全局解释器锁(GIL)限制了解释器中同一时间只能有一个线程执行Python字节码。如果需要实现真正的并行执行,可以使用多进程(multiprocessing模块)或者其他第三方库(如concurrent.futures)来实现。
Python 的多线程更适合于 I/O 密集型的任务,而不是 CPU 密集型的任务。单线程下有IO操作时,会进行IO等待,这样会浪费等待的这段时间,而开启多线程能在线程A等待时,自动切换到线程B,可以减少不必要的时间浪费,从而能提升程序运行效率。但是也不是最好的选择,对于处理IO密集型任务,在Python还有更好的选择协程。

1.函数调用

import threadingdef task():# 线程的任务print('111')threading.Thread(target=task, name='dance').start()

2.类的调用

import threadingclass MyThread(threading.Thread):def __init__(self):super().__init__()# self.num = num # 自定义参数def run(self):# 线程的任务print('111')return 'ok'if __name__ == '__main__':my = MyThread()# 如果有参数# my = MyThread(num=1)my.start()

三、共享全局变量

"""多线程共享全局变量"""
import threading
import timeg_num = 100  # 这个要使用global
list = [1,2]  # 这个在函数中执行的时候要是不改变他的指向就不需要使用globaldef test1():"""改变全局变量"""global g_numg_num += 1list.append(1)print('-----test1----g_num:%d----' % g_num)print(f'list初始:[1,2]检查是否可以在不使用global的情况下使用全局变量:{list}')def test2():"""打印全局变量g_num,如果共享则打印的全局变量为101"""global g_numprint('----test2----g_num:%d----' % g_num)print(f'----test2----list:{list}----')def main():t1 = threading.Thread(target=test1)t2 = threading.Thread(target=test2)t1.start()time.sleep(1)  # 确保test1先执行t2.start()time.sleep(1)print('----in main g_num = %d----' % g_num)if __name__ == '__main__':main()

互斥锁建议参考:python多线程讲解_V-Sugar的博客-CSDN博客

四、守护线程

在 Python 中,线程对象的 daemon 属性用于指定线程的守护状态。一个守护线程是指在主线程退出时会被强制终止的线程。如果一个线程被设置为守护线程,那么当最后一个非守护线程退出时,守护线程也会立即退出,不管它是否完成了自己的任务。

可以通过线程对象的 setDaemon() 方法将线程设置为守护线程。该方法接受一个布尔值参数,True 表示将线程设置为守护线程,False 表示将线程设置为非守护线程。

下面是一个示例代码,演示了如何创建和设置守护线程:

import threading
import timedef print_numbers():for i in range(1, 6):print(i)time.sleep(1)# 创建线程对象
thread = threading.Thread(target=print_numbers)# 设置线程为守护线程
thread.setDaemon(True)# 启动线程
thread.start()# 主线程休眠3秒
time.sleep(3)# 主线程结束,守护线程也会立即退出
print("Main thread exiting...")

在上面的例子中,我们创建了一个线程对象,并将它设置为守护线程。当主线程休眠了3秒之后,主线程结束并退出,守护线程也会立即退出,即使它没执行完毕。

需要注意的是,守护线程不应该执行一些重要的任务,因为在主线程退出时守护线程会被强制终止,可能导致任务未完成或数据不一致。守护线程通常用于执行一些后台或周期性的任务,如日志记录、定时器等。

五、线程锁

在 Python 中,可以使用线程锁(Thread Lock)来确保在多线程环境下的数据同步和线程安全。线程锁是一种同步机制,可以防止多个线程同时访问共享资源,从而避免出现数据竞争和不一致的情况。

Python 提供了 threading 模块中的 Lock 类来实现线程锁。可以使用 Lock 类的 acquire() 方法获取锁,在执行需要同步的代码块之前,需要先获取锁。在代码块执行完毕后,使用 release() 方法释放锁,让其他线程可以获取锁并继续执行。

下面是一个示例代码,演示了如何使用线程锁:

import threading# 创建一个线程锁对象
lock = threading.Lock()# 共享资源
counter = 0def increment():global counter# 获取锁lock.acquire()# 访问共享资源counter += 1# 释放锁lock.release()# 创建多个线程
threads = []
for _ in range(10):thread = threading.Thread(target=increment)threads.append(thread)# 启动线程
for thread in threads:thread.start()# 等待所有线程执行完毕
for thread in threads:thread.join()# 打印最终结果
print("Final counter value:", counter)

在上面的例子中,我们创建了一个线程锁对象,并定义了一个共享资源 counter。在 increment() 函数中,我们首先使用 acquire() 方法获取锁,然后对 counter 进行递增操作,最后使用 release() 方法释放锁。

通过使用线程锁,我们确保了在每个线程访问 counter 时,只有一个线程可以获取锁并执行递增操作,从而保证了最终结果的正确性。

需要注意的是,在使用线程锁时需要小心避免出现死锁(Deadlock)情况。当多个线程相互等待对方释放锁时,可能会导致死锁的发生,使得程序无法继续执行。因此,在设计多线程程序时,需要合理地使用锁,避免出现潜在的死锁问题。

如果使用with的话,可以不用acquire和release。

def increment():global counterwith lock:# 访问共享资源counter += 1

六、杀死进程

import os
import threadingdef kill(pid):# 本函数用于中止传入pid所对应的进程if os.name == 'nt':# Windows系统cmd = 'taskkill /pid ' + str(pid) + ' /f'try:os.system(cmd)print(pid, 'killed')except Exception as e:print(e)elif os.name == 'posix':# Linux系统cmd = 'kill ' + str(pid)try:os.system(cmd)print(pid, 'killed')except Exception as e:print(e)else:print('Undefined os.name')class MyThread(threading.Thread):def __init__(self):super().__init__()# self.num = num # 自定义参数def run(self):# 线程的任务print('111')return 'ok'if __name__ == '__main__':# 1.读取上次保存的pidf1 = open(file='feishu_pid.txt', mode='r')pid = f1.read()f1.close()# 2.如果存在杀死上一次的进程print('上一次进程', pid)if pid:# 调用kill函数,终止进程kill(pid=pid)# 3.获取当前进程的pidpid = os.getpid()print('当前进程的pid: ', pid)# 4.将pid写入本地文件,供下次调用f2 = open(file='feishu_pid.txt', mode='w')f2.write(pid.__str__())f2.close()# 5.开启新的线程my = MyThread()# 如果有参数# my = MyThread(num=1)my.start()

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

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

相关文章

java数据结构与算法刷题-----LeetCode70. 爬楼梯

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只…

巨杉数据库荣登2023胡润全球猎豹企业榜

胡润研究院与广州南沙联合发布《2023胡润全球猎豹企业榜》,这是胡润研究院首次发布“全球猎豹企业”。榜单列出了全球成立于2000年后,五年内最有可能达到独角兽级十亿美金估值的高成长性企业。巨杉数据库凭借在分布式文档型数据库领域的创新突破&#xf…

理解机器学习中的术语

文章目录 求导,梯度代码实现 求导,梯度 高等数学中一个函数 y f ( x ) y f(x) yf(x)假设这个函数表示求出速度 , y ( 速度 k m / h ) 1000 ( m ) x ( 小时 h ) y(速度km/h) \frac{1000(m)}{x(小时 h)} y(速度km/h)x(小时h)1000(m)​那么…

「HarmonyOS」验证码多TextInput输入框焦点自动跳转问题

需求背景:需要做一个多输入框的验证码模块,输入验证码时输入后光标会自动跳转至下一个输入框,删除验证码时会自动删除上一个输入框内容,并且光标跳转至上一个输入框内。6位验证码全部输完后进行登录请求 具体样式如下图&#xff1…

mysql:SQL按时间查询方法总结

查询当天数据: select * from 表名 where to_days(时间字段名) = to_days(now()); 查询昨天数据: SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 时间字段名) = 1 查询近7天数据: SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(时…

Android 收集崩溃(crash)日志并输出到本地

DefaultUncaughtExceptionHandler 是 Android 中的一个接口&#xff0c;用于处理未捕获异常。默认情况下&#xff0c;Android 系统有一个默认的未捕获异常处理器&#xff08;Thread.defaultUncaughtExceptionHandler&#xff09;当程序抛出未捕获的异常时&#xff0c;系统会调用…

通信网络(2)——DAI技术

一、简介 在今天的测试脚本过程中&#xff0c;遇到了ARP防攻击基于VLAN的DAI防攻击知识点&#xff0c;因此本篇文章将用于介绍为何DAI技术 二、DAI技术介绍 DAI技术是思科的一种技术&#xff0c;全称为Dynamic ARP Inspection&#xff0c;顾名思义动态ARP选择&#xff0c;这…

快速跳闸中间继电器 RXMS1-RK216 066-AD 24V 柜内安装,板后接线带中座

系列型号 RXMS1 RK 216 437快速跳闸继电器&#xff1b;RXMS1 RK 216 237快速跳闸继电器&#xff1b; RXMS1 RK 216 449快速跳闸继电器&#xff1b;RXMS1 RK 216 249快速跳闸继电器&#xff1b; RXMS1 RK 216 450快速跳闸继电器&#xff1b;RXMS1 RK 216 250快速跳闸继电器&…

three.js Raycaster(鼠标点击选中模型)

效果&#xff1a; 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div class"box-right"…

搜索与人工智能

前言 第一&#xff1a;通过博弈树搜索和启发式搜索的例子 了解基于搜索的通用问题求解方法 第二&#xff1a;了解人工智能发展的历程和社会影响 第三&#xff1a;了解机器学习的基本思想和典型应用 第四&#xff1a;了解人工智能应用开发的基本模式 内容 1.博弈树与剪纸…

URLConnection()和openStream()两个方法产生SSRF的原理和修复方法

今年是自主研发的第三个年份&#xff0c;也是重视安全的年份。 转一篇小文章&#xff1a; 0x00 前言 SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定 URL 地址获取网页文本内容&#xff0c;加载指定地址的图…

Redis 过期策略

我们在set key的时候可以设置key的过期时间&#xff0c;哪redis是怎么处理过期的key的呢&#xff1f; 有三种过期策略 定时过期&#xff1a;每个设置过期时间的key会创建一个定时器&#xff0c;到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据&#xff0c;对…

*JavaScript

*JavaScript ECMAScript: 数据类型和变量&#xff0c;选择结构&#xff0c;循环结构&#xff0c;对象&#xff0c;数组&#xff0c;函数&#xff0c;运算符(ES6特性) DOM: 文档对象模型 -Document:每个载入浏览器的 HTML 文档都会成为 Document 对象 节点获取&#xff1a; …

VR云游开启智慧旅游新纪元,打造“云旅游”新模式

元旦假期&#xff0c;全国文化和旅游市场平稳有序&#xff0c;家人和亲友的出游趋势稳步增加&#xff0c;演唱会、音乐节、跨年等活动的叠加让元旦出游更加吸引游客。在冰雪旅游热度持续攀升的时候&#xff0c;许多年轻群体已经开始使用VR云游进行智慧景区旅游&#xff0c;身临…

项目代码生成心得

1、如果一直ctrl B 生成不了代码&#xff0c;可能是卡住了&#xff0c;要run一下才行 2、sub chart里面千万不要加上内部自转移和en,du:不然里面的内容压根不会生成代码&#xff0c;Matlab认为它可以自己在里面自己转。 3、生成的代码跟设计图是不一样的&#xff01;&#xff…

Databend 的算力可扩展性

作者&#xff1a;尚卓燃&#xff08;PsiACE&#xff09; 澳门科技大学在读硕士&#xff0c;Databend 研发工程师实习生 Apache OpenDAL(Incubating) Committer PsiACE (Chojan Shang) GitHub 对于大规模分布式数据处理系统&#xff0c;为了更好应对数据、流量、和复杂性的增长…

CRYPTO现代密码学学习

CRYPTO现代密码学学习 RC4 加密算法RSA加密解密DES加密解密详解密钥的生成密文的生成 RC4 加密算法 简单介绍&#xff1a;RC4加密算法是一种对称加密算法&#xff0c;加密和解密使用同一个函数 初始化分为以下几个步骤 初始化存储0-255字节的Sbox(其实就是一个数组)填充key到…

爬虫工具(tkinter+scrapy+pyinstaller)

需求介绍输入&#xff1a;关键字文件&#xff0c;每一行数据为一爬取单元。若一行存在多个and关系的关键字 &#xff0c;则用|隔开处理&#xff1a;爬取访问6个网站的推送&#xff0c;获取推送内容的标题&#xff0c;发布时间&#xff0c;来源&#xff0c;正文第一段&#xff0…

Linux Kdump和Crash工具

Kdump Kdump是一种基于kexec的Linux内核崩溃捕获机制&#xff0c;简单来说系统启动时会预留一块内存&#xff0c;当系统崩溃调用命令kexec(kdump kernel)在预留的内存中启动kdump内核&#xff0c; 该内核会将此时内存中的所有运行状态和数据信息收集到一个coredump文件中以便…

【服务器】安装Node.js开发环境

部署Node.js环境(使用NVM安装多个Node.js版本): NVM&#xff08;Node VersionManager&#xff09;是Node.js的版本管理软件&#xff0c;使您可以轻松在Node.js各个版本间进行切换。适用于长期做node开发的人员或有快速更新node版本、快速切换node版本的场景。 具体操作步骤如…