python多线程互斥锁与死锁问题详解

 更新时间:2022年01月27日 15:58:58   作者:陈小c  
大家好,本篇文章主要讲的是python多线程互斥锁与死锁问题详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

一、多线程共享全局变量

代码实现的功能:

创建work01与worker02函数,对全局变量进行加一操作创建main函数,生成两个线程,同时调用两个函数

代码如下:

import threading

result = 0  # 定义全局变量result
def work1(num):
    global result
    for i in range(num):
        result += 1
    print('------from work1-------', result)


def work2(num):
    global result
    for i in range(num):
        result += 1
    print('------from work2-------', result)


def main():
    print('--------begin--------', result)
    # 创建两个线程
    t1 = threading.Thread(target=work1, args=(1000,))
    t2 = threading.Thread(target=work1, args=(1000,))
    t1.start()
    t2.start()

if __name__ == '__main__':
    main()

运行结果:

--------begin---------- 0
------from work1------- 1000
------from work1------- 2000

两个线程之间共享了全局变量result,但是当我们把range的数值调大一些,

    t1 = threading.Thread(target=work1, args=(1000000,))
    t2 = threading.Thread(target=work1, args=(1000000,))

我们再来看一下结果,这是为什么呢,我们往下看一下结果:

--------begin---------- 0
------from work1------- 1358452
------from work1------- 1696352

总结:
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

二、给线程加一把锁锁

假如当前 g_num 值是100,当线程1执行第一步时,cpu通过计算获得结果101,并准备把计算的结果101赋值给g_num,然后再传值的过程中,线程2突然开始执行了并且执行了第一步,此时g_num的值仍未100,101还在传递的过程中,还没成功赋值,线程2获得计算结果101,并准备传递给g_num,经过一来一去这么一折腾,分明做了两次加 1 操作,g_num结果却是101,误差就由此产生,往往循环次数越多,产生的误差就越大,此时我们可以加一把锁。

acquire() — 锁定资源,此时资源是锁定状态,其他线程无法修改锁定的资源,直到等待锁定的资源释放之后才能操作;

release() — 释放资源,也称为解锁操作,对锁定的资源解锁,解锁之后其他线程可以对资源正常操作;

以上面的代码为列子:想得到正确的结果,可以直接利用互斥锁在全局变量 加1 之前 锁定资源,然后在计算完成之后释放资源,这样就是一个完整的计算过程,至于应该是哪个线程先执行,无所谓,先到先得,凭本事说话….演示代码如下:

# 开发时间:2022-01-27 12:59
import threading

result = 0  # 定义全局变量result
mutex = threading.Lock()

def work1(num):
    global result
    mutex.acquire()
    for i in range(num):
        result += 1
    print('------from work1-------', result)
    mutex.release()


def work2(num):
    global result
    mutex.acquire()
    for i in range(num):
        result += 1
    print('------from work2-------', result)
    mutex.release()


def main():
    print('--------begin----------', result)
    # 创建两个线程
    t1 = threading.Thread(target=work1, args=(100000000,))
    t2 = threading.Thread(target=work1, args=(100000000,))
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

我们来看一下结果:

--------begin---------- 0
------from work1------- 100000000
------from work1------- 200000000

三、死锁问题

1.单个互斥锁的死锁:

acquire()/release() 是成对出现的,互斥锁对资源锁定之后就一定要解锁,否则资源会一直处于锁定状态,其他线程无法修改;就好比上面的代码,任何一个线程没有释放资源release(),程序就会一直处于阻塞状态(在等待资源被释放),不信你可以试一试~

2.多个互斥锁的死锁:

在同时操作多个互斥锁的时候一定要格外小心,因为一不小心就容易进入死循环,假如有这样一个场景:boss让程序员一实现功能一的开发,让程序员二实现功能二的开发,功能开发完成之后一起整合代码!

# 导入线程threading模块
import threading
# 导入线程time模块
import time

# 创建互斥锁
mutex_one = threading.Lock()
mutex_two = threading.Lock()


def programmer_thread1():
    mutex_one.acquire()
    print("我是程序员1,module1开发正式开始,程序一加锁,程序二加锁")
    time.sleep(2)

    # 此时会堵塞,因为这个mutex_two已经被线程programmer_thread2抢先上锁了,等待解锁
    mutex_two.acquire()
    print("等待程序员2通知我合并代码")
    mutex_two.release()
    print('程序员2开发完了,程序员1释放第二把锁')

    mutex_one.release()
    print('程序员1开发完了,程序员1释放第一把锁')


def programmer_thread2():
    mutex_two.acquire()
    print("我是程序员2,module2开发正式开始,程序二加锁,程序一加锁")
    time.sleep(2)
    # 此时会堵塞,因为这个mutex_one已经被线程programmer_thread1抢先上锁了,等待解锁
    #mutex_two.release()
    mutex_one.acquire()
    print("等待程序员1通知我合并代码")
    mutex_one.release()
    print('程序员2释放第一把锁')
   # mutex_two.release()
    print('程序员2释放第二把锁')


def main():
    t1 = threading.Thread(target=programmer_thread1)
    t2 = threading.Thread(target=programmer_thread2)

    # 启动线程
    t1.start()
    t2.start()
    # 阻塞函数,等待线程结束
    t1.join()
    t2.join()
    # 整合代码结束
    print("整合代码结束 ")


if __name__ == "__main__":
    main()

分析下上面代码:程序员1在等程序员2通知,程序员2在等程序员1通知,两个线程都陷入阻塞中,因为两个线程都在等待对方解锁,这就是死锁!所以在开发中对于死锁的问题还是需要多多注意!

总结

到此这篇关于python多线程互斥锁与死锁问题详解的文章就介绍到这了,更多相关python互斥锁与死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python多线程互斥锁与死锁问题详解

    python多线程互斥锁与死锁问题详解

    大家好,本篇文章主要讲的是python多线程互斥锁与死锁问题详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 提升python处理速度原理及方法实例

    提升python处理速度原理及方法实例

    这篇文章主要介绍了提升python处理速度原理及方法实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Python检查端口是否打开的七种方法总结

    Python检查端口是否打开的七种方法总结

    在信息安全领域,端口扫描是一项常见的技术,用于逐个检测目标主机上的端口是否开放,这篇文章主要给大家介绍了关于Python检查端口是否打开的七种方法总结,需要的朋友可以参考下
    2023-12-12
  • 使用Tensorflow hub完成目标检测过程详解

    使用Tensorflow hub完成目标检测过程详解

    这篇文章主要为大家介绍了使用Tensorflow hub完成目标检测过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • python中if-elif-else语句实例用法讲解

    python中if-elif-else语句实例用法讲解

    在本篇文章里小编给大家整理的是一篇关于python中if-elif-else语句的使用注意事项,有需要的便宜么可以跟着参考下。
    2021-10-10
  • Django中使用 Closure Table 储存无限分级数据

    Django中使用 Closure Table 储存无限分级数据

    对于数据量大的情况(比如用户之间有邀请链,有点三级分销的意思),就要用到 closure table 的结构来进行存储。这篇文章主要介绍了Django中使用 Closure Table 储存无限分级数据,需要的朋友可以参考下
    2019-06-06
  • 用Anaconda安装本地python包的方法及路径问题(图文)

    用Anaconda安装本地python包的方法及路径问题(图文)

    这篇文章主要介绍了用Anaconda安装本地python包的方法及路径问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-07-07
  • pytorch中的优化器optimizer.param_groups用法

    pytorch中的优化器optimizer.param_groups用法

    这篇文章主要介绍了pytorch中的优化器optimizer.param_groups用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-05-05
  • Python运行不显示DOS窗口的解决方法

    Python运行不显示DOS窗口的解决方法

    今天小编就为大家分享一篇Python运行不显示DOS窗口的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • python实现的分析并统计nginx日志数据功能示例

    python实现的分析并统计nginx日志数据功能示例

    这篇文章主要介绍了python实现的分析并统计nginx日志数据功能,结合实例形式分析了Python针对nginx日志ip、访问url、状态等数据的相关读取、解析操作技巧,需要的朋友可以参考下
    2019-12-12

最新评论