关于Python死锁问题的问题?

前面说到过Python死锁问题多线程的基夲使用大概的内容有几点

后面又说了两个点就是join和守护线程的概念

但是不知道大家有没有注意到一点就是前面说的两个功能是相互独立嘚,相互不干涉的不会用到同享的资源或者数据,如果我们多个线程要用到相同的数据那么就会存在资源争用和锁的问题,不管在什麼语言中这个都是不能避免的。对数据库属性的同学应该也了解数据库中也存在锁的概念。

今天这篇文章我们说说Python死锁问题多线程中嘚同步锁死锁和递归锁的使用。

锁通常被用来实现对共享资源的同步访问为每一个共享资源创建一个Lock对象,当你需要访问该资源时調用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放)待资源访问完后,再调用release方法释放锁

下面我们來举个例子说明如果多线程在没有同步锁的情况下访问公共资源会导致什么情况

上面的例子其实很简单就是创建100的线程,然后每个线程去從公共资源num变量去执行减1操作按照正常情况下面,等到代码执行结束打印num变量,应该得到的是0因为100个线程都去执行了一次减1的操作。

但是结果却不是我们想想的我们看看结果

我们会发现,每次执行的结果num值都不是一样的上面显示的是91,那就存在问题了为什么结果不是0呢?

我们来看看上面代码的执行流程
1.因为GIL,只有一个线程(假设线程1)拿到了num这个资源然后把变量赋值给num2,sleep 0.001秒,这时候num=100
2.当第一个線程sleep 0.001秒这个期间这个线程会做yield操作,就是把cpu切换给别的线程执行(假设线程2拿到个GIL获得cpu使用权),线程2也和线程1一样也拿到num,返回赋值給num2然sleep,这时候,其实num还是=100.
3.线程2 sleep时候又要yield操作,假设线程3拿到num,执行上面的操作其实num有可能还是100
4.等到后面cpu重新切换给线程1,线程2线程3上執行的时候,他们执行减1操作后其实等到的num其实都是99,而不是顺序递减的
5.其他剩余的线程操作如上

大家应该发现问题了,结果和我们想想的不一样那我们怎么才能等到我们想要的结果呢?就是100个线程操作num变量得到最后结果为0

这里就要借助于Python死锁问题的同步锁了,也僦是同一时间只能放一个线程来操作num变量减1之后,后面的线程操作来操作num变量看看下面我们怎么实现。

看到上面我们给中间的减1代码塊加个一把同步锁,这样我们就可以得到我们想要的结果了,这就是同步锁的作用一次只有一个线程操作同享资源。

看看上面代码執行的结果:

现在操作共享资源的线程名字是: Thread-98 现在操作共享资源的线程名字是: Thread-100

死锁的这个概念在很多地方都存在比较在数据中,大概介紹下私有是怎么产生的
3.A现在想再拿个香蕉就在等待B释放这个香蕉
4.B同时想要再拿个苹果,这时候就等待A释放苹果
5.这样就是陷入了僵局这僦是生活中的死锁

Python死锁问题中在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源就会造成死锁,因为系统判断这部分资源都正在使用所有这两个线程在无外力作用下将一直等待下去。下面是一个死锁的例子:

代码执行hung住死锁了

仩面的代码其实就是描述了苹果和香蕉的故事。大家可以仔细看看过程下面我们看看执行流程

1.fun1中,线程1先拿了苹果然后拿了香蕉,然後释放香蕉和苹果然后再在fun2中又拿了香蕉,sleep 0.1秒
2.在线程1的执行过程中,线程2进入了因为苹果被线程1释放了,线程2这时候获得了苹果嘫后想拿香蕉
3.这时候就出现问题了,线程一拿完香蕉之后想拿苹果返现苹果被线程2拿到了,线程2拿到苹果执行想拿香蕉,发现香蕉被線程1持有了
4.双向等待出现死锁,代码执行不下去了

上面就是大概的执行流程和死锁出现的原因在这种情况下就是在同一线程中多次请求同一资源时候出现的问题。

为了支持在同一线程中多次请求同一资源Python死锁问题提供了"递归锁":threading.RLock。RLock内部维护着一个Lock和一个counter变量counter记录了acquire嘚次数,从而使得资源可以被多次acquire直到一个线程所有的acquire都被release,其他的线程才能获得资源

下面我们用递归锁RLock解决上面的死锁问题

上面我們用一把递归锁,就解决了多个同步锁导致的死锁问题大家可以把RLock理解为大锁中还有小锁,只有等到内部所有的小锁都没有了,其他嘚线程才能进入这个公共资源

另外一点前面没有就算用类继承的方法实现Python死锁问题多线程,这个大家可以查下就算继承Thread类,然后重新run方法来实现

最后大家可能还有个疑问,就算如果我们都加锁了也就是单线程了,那我们还要开多线程有什么用呢这里解释下,在访問共享资源的时候锁是一定要存在了,但是我们的代码中不是总是在访问公共资源的还有一些其他的逻辑可以使用多线程,所以我们茬代码里面加锁的时候要注意在什么地方加,对性能的影响最小这个就靠对逻辑的理解了。

好了今天就说到这里个人意见,望指教

死锁的结果跟解法的结果

运行之後同样是这样的结果

请问死锁的结果跟其他解法的结果在哪儿有不同之处

将你两种不同的结果贴上来瞧瞧

您好,抱歉一时没看到您的回複 这个是运行死锁的结果

这个是运行waiters解法的结果

这个是运行index解法的结果

请问这些结果差异在哪里如果有的话,这些差异又代表什么意思呢

在第一种有死锁的情况下,你运行时间长一些会发现系统不打印文字出来了(哲学家们都不吃东西了!),这是因为发生了死锁的緣故

而在我们的waiter以及index解法下不会出现死锁,系统会一直打印文字大哲们会一直吃下去的!

我要回帖

更多关于 python 的文章

 

随机推荐