浅谈python多线程和多线程变量共享问题介绍
作者:Record learning 发布时间:2022-08-29 04:34:18
标签:python,多线程,变量共享
1、demo
第一个代码是多线程的简单使用,编写了线程如何执行函数和类。
import threading
import time
class ClassName(threading.Thread):
"""创建类,通过多线程执行"""
def run(self):
for i in range(5):
print(i)
time.sleep(1)
def sing():
for i in range(1,11):
print("唱歌第 %d 遍" % i)
time.sleep(1)
def dance():
for i in range(1,16):
print("跳舞第 %d 遍" % i)
time.sleep(1)
def main():
t1 = threading.Thread(target = sing)
t2 = threading.Thread(target = dance)
t = ClassName()
# 启动线程
t1.start()
t2.start()
t.start()
while True:
length = len(threading.enumerate())
print("正在运行的线程有 %s" %threading.enumerate())
if length <= 1:
break
time.sleep(1)
if __name__ == '__main__':
main()
执行结果可以看到函数 sing、dance和类在同时执行,执行效果太长就不方截图了
2、多线程共享变量
通过定义全局变量,然后再test1函数类部进行更改全局变量,test2打印全局变量。
import threading
import time
#定义全局变量
g_num = 0
def test1():
"""函数test1对全局变量进行更改"""
global g_num
for i in range(1,10):
g_num += 1
print("--- test1 线程 g_num = %d--- " % g_num)
def test2():
"""函数test2 打印全局变量"""
print("--- test2 线程 g_num = %d--- " % g_num)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
# 启动线程
t1.start()
# 增加睡眠是为了保证优先执行函数test1
time.sleep(1)
t2.start()
print("--- 主线程 g_num = %d--- " % g_num)
if __name__ == '__main__':
main()
执行结果可以看出,在主线程和创建的两个线程中读取的是一样的值,既可以表明在多线程中变量共享
3、资源竞争
在多线程两个函数中同时更改一个变量时,由于cpu的计算能力,当修改参数的代码块无法一次性执行完成时,就会产生资源竞争
import threading
import time
# 定义全局变量
g_num = 0
def test1(num):
"""函数test1对全局变量进行更改"""
global g_num
for i in range(num):
g_num += 1
print("test1 线程 g_num = %d---" % g_num)
def test2(num):
"""函数test2对全局变量进行更改"""
global g_num
for i in range(num):
g_num += 1
print("tes2 线程 g_num = %d---" % g_num)
def main():
t1 = threading.Thread(target=test1, args=(1000000, ))
t2 = threading.Thread(target=test2, args=(1000000, ))
t1.start()
t2.start()
time.sleep(1)
print("主线程 g_num = %d---" % g_num)
if __name__ == '__main__':
main()
可以先试试传递参数为100时,可以看到g_num = 200 这是因为函数代码可以一次性执行完成,当参数为1000000时代码无法一次性执行完成,g_num!= 2000000
4、互斥锁
互斥锁可以解决资源竞争的问题,原理很简单,通过对代码块上锁,保证该代码执行完成前,其它代码无法进行修改。执行完成后解锁,其它代码就可以执行了。
import threading
import time
# 创建变量
g_num = 0
# 创建锁默认为开锁状态
mutex = threading.Lock()
def test1(num):
global g_num
for i in range(num):
# 上锁
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
print("--- test1 线程 g_num = %d---" % g_num)
def test2(num):
global g_num
for i in range(num):
# 上锁
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
print("--- test2 线程 g_num = %d---" % g_num)
def main():
t1 = threading.Thread(target=test1, args=(1000000, ))
t2 = threading.Thread(target=test2, args=(1000000, ))
t1.start()
t2.start()
time.sleep(1)
print("--- 主线程 g_num = %d---" % g_num)
if __name__ == '__main__':
main()
可以看到加了锁之后,代码执行不会出现资源竞争,结果也是正常的。互斥锁,上锁的代码越少越好。
5、死锁
当出现多个锁时,就可能会产生死锁这个情况。当关闭一个锁时,这个锁已经为关闭状态的话,程序就会阻塞。就如同下面这个代码中。函数test1关闭mutexB锁时,函数test2提前将其关闭了,未进行解锁,程序就会一直阻塞。
import threading
import time
# 创建两个锁A, B
mutexA = threading.Lock()
mutexB = threading.Lock()
def test1():
# 对muctexA上锁
mutexA.acquire()
# mutexA上锁后,延时1秒,等待mutexB上锁
print("test1 ---do1---up---")
time.sleep(1)
# 此时会堵塞,因为mutexB已经上锁
mutexB.acquire()
print("test1 ---do1---down---")
mutexB.release()
# 对mutexA解锁
mutexA.release()
def test2():
# 对muctexB上锁
mutexB.acquire()
# mutexB上锁后,延时1秒,等待mutexA上锁
print("test2 ---do1---up---")
time.sleep(1)
# 此时会堵塞,因为mutexB已经上锁
mutexA.acquire()
print("test2 ---do1---down---")
mutexA.release()
# 对mutexA解锁
mutexB.release()
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
代码执行效果可以看到程序会一直阻塞
解决方法
1、在程序编写时,就需要注意避免死锁
2、可以参考银行家算法
来源:https://blog.csdn.net/qq_40483425/article/details/105521392
0
投稿
猜你喜欢
- 思想:4个数字的排列,加上3个运算符的排列,使用后缀表达式的表现如下:情形一:1,2,3,4,+,-,* => 24*24*4情形二:
- python中with可以明显改进代码友好度,比如:with open('a.txt') as f:  
- 定义线程最简单的方法:使用target指定线程要执行的目标函数,再使用start()启动。语法:class threading.Thread
- 常见的图片加密方法包括加密算法、水印、隐藏、压缩等。下面简要介绍一些常见的图片加密方法:加密算法加密算法是一种基于数学运算的加密方式,可对图
- 文章背景:某天,我的一个同事给我看了CSDN上面的一篇关于编程语言排行榜的文章,里面我看到VB还是排名很不错的,我就说,asp(vbscri
- 如下图,我们在做图片logo列表的时候通常是用li标签来实现。html:<ul class="logolist&q
- 本文实例讲述了django+js+ajax实现刷新页面的方法。分享给大家供大家参考,具体如下:在服务器开发的时候,为了方便将服务器对外开一个
- clipboardData 对象提供了对于预定义的剪贴板格式的访问,以便在编辑操作中使用。成员表方法 描述 clearData 通过 dat
- 即使是简单的脚本语言,应用良好的模式可以得到非常“优美”的代码和较高的效率。尤其是对于交互要求较高的B/S系统,非常有必要用设计模式来优化代
- 前言通常执行 python 程序要有相应的 Python 环境,但某些特定场景下,我们可能并不愿意这么麻烦的去配置这些环境(比如将写好的脚本
- 输出电脑上所有的串口名:import serialimport serial.tools.list_portsfrom easygui im
- pytorch的dataloader会将数据传到GPU上,这个过程GPU的mem占用会逐渐增加,为了避免GPUmen被无用的数据占用,可以在
- 一、安装pip2pi工具:pip install pip2pi或:git clone https://github.com/wolever/
- 今天在工作中遇到了一个问题,需要按时间查询,可是查询出来的结果显示的不正确。举个例子来说,要查找出2007-10-12至2007-10-31
- python 字符串下标与切片的实例代码,如下:# !/usr/bin/env pythonname = "ksunone&quo
- 一、前期准备 此篇使用两种导入excel数据的
- 前言对于很多接触Python的人而言,字符的处理和语言整体的温顺可靠相比显得格外桀骜不驯难以驾驭。文章针对Python 2.7,主要因为3对
- 好久没有更新过PyQt5相关的专题了,今天正好有空就做一个文件、文件内容检索的小工具。目的是为了能够很快的完成的在任意磁盘路径下找到我们需要
- 系统自带模块(库)```cppimport retarget = 'abc1234xyz're.search('(\
- python的便利性,使得如今许多软件开发者、黑客都开始使用python打包成exe的方式进行程序的发布,这类exe有个特点,就是可以使用反