您的位置:首页 > 编程语言 > Python开发

Python多任务学习笔记(4)——多线程共享全局变量产生问题的解决方案之互斥锁

2020-04-19 23:06 316 查看

文章目录

Python多任务学习笔记(3)——多线程共享全局变量及可能产生的问题中,我们知道Python中多线程共享全局变量,但是这会产生如前文中所描述的问题,name应该如何解决这个问题呢?

1. 线程同步的概念

此处不是取同时之意,而是取协同、配合之意,比如在前述Python多线程中,线程1和2之间应该协同递增变量global_num的值,而不是同时,否则就会产生意料之外的情形。

具体来说,以Python多任务学习笔记(3)——多线程共享全局变量及可能产生的问题中的情形为例,如果可以实现:线程1在执行语句global_num += 1时,线程2无法修改global_num的值;反之线程2在执行语句global_num += 1时,线程1也无法修改global_num的值。这种功能就可以叫线程同步

2. 线程同步的实现——互斥锁

互斥锁是最简单的一种线程同步机制,可简单将其理解为可以对多线程共享的资源进行锁定的操作。

如:还是以Python多任务学习笔记(3)——多线程共享全局变量及可能产生的问题中的情形为例,如果某个线程想要修改其和另一条线程共享的全局变量global_num(即资源),该线程可对其进行上锁,这样另一条线程就无法修改该全局变量,等到该线程成功修改该全局变量后,再将该全局变量解锁,则另一条线程便也可对其执行上锁操作后修改其值,如此循环往复,就解决了意料之外的情形。

3. Python中互斥锁的实现

Python中的threading模块中提供的Lock类实现了互斥锁。

针对Python多任务学习笔记(3)——多线程共享全局变量及可能产生的问题中的情形,通过Python中的互斥锁,有以下代码可解决问题:

import threading

# 定义一个全局变量
global_num = 0

def test1(num):
global global_num
for i in range(num):
# 为互斥锁上锁,如果之前未被其他线程上锁,则上锁成功
# 否则,阻塞直到其他线程解锁后才成功上锁
mutual_lock.acquire()

global_num += 1
mutual_lock.release()

print("Inside the Thread Denoted by "
"Function test1() global_num = %d" % global_num)

def test2(num):
global global_num
for i in range(num):
mutual_lock.acquire()
global_num += 1
mutual_lock.release()

print("Inside the Thread Denoted by "
"Function test2() global_num = %d" % global_num)

# 创建一全局互斥锁对象
mutual_lock = threading.Lock()

def main():
thread1 = threading.Thread(target=test1, args=(1000000,))
thread2 = threading.Thread(target=test2, args=(1000000,))
thread1.start()
thread2.start()

# 等待两个线程均运行结束
while True:
if len(threading.enumerate()) == 1:
break

print("Inside the Main Thread num = %d" % global_num)

if __name__ == "__main__":
main()

上述代码的运行结果为:

Inside the Thread Denoted by Function test2() global_num = 1853037
Inside the Thread Denoted by Function test1() global_num = 2000000
Inside the Main Thread global_num = 2000000

值得注意的是,上述采用互斥锁的代码在运行之后,虽然保证了最终结果的准确性,即global_num最终为2000000,但是在子线程2中,最终打印为1853037。

产生上述现象的原因在于,CPU通过时间片轮转的方式调度线程时并非完全雨露均沾(即线程1、2按照各自一次的频率对global_num进行累加),也就是说:可能线程2在解锁后,线程1并没有能够马上获取锁,而是线程2又获取了锁,最后导致线程2抢先完成1000000次增加,而此时线程1仅完成了853037次,由此造成了此现象。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
TakingCoding4Granted 发布了37 篇原创文章 · 获赞 1 · 访问量 1279 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: