python threading condition使用_多线程中的Condition对象

python多线程模块threading中,有一个Condition对象。这个对象可以用来控制更加复杂的线程间的同步。

Condition本身包含一个Lock或者Rlock,可以在创建Congdition对象的时候传一个进去,如果不传,默认创建一个Rlock。通过with语句,即可acquire,并且自动release。不过这不是Condition对象的用法,它的亮点在于wait和notify。

在通过with语句获取lock之后,线程可以通过wait,release这个lock,并且block。或者线程可以通过notify,让渡(relinquish)自己的lock给在这个condition对象上wait的线程用。

Note: the notify() and notify_all() methods don’t release the lock; this means that the thread or threads awakened will not return from their wait() call immediately, but only when the thread that called notify() or notify_all() finally relinquishes ownership of the lock.

notify之后,wait在那个condition上的thread,不会离开从wait返回,而是等待调用notify的thread执行完它的代码逻辑,relinquish ownership of the lock。即明确指示wait在那个condition上的thread执行(用notify_all,就需要在一个范围内随机调度)。好性感的操控!

from time import sleep

from threading import Thread, Lock, Condition

mutex = Lock()

conv = Condition(mutex)

def target1():

with conv:

print(1)

sleep(2)

conv.notify()

conv.wait()

print(3)

sleep(2)

conv.notify()

conv.wait()

print(5)

sleep(2)

conv.notify()

conv.wait()

print(7)

conv.notify()

def target2():

with conv:

print(2)

sleep(2)

conv.notify()

conv.wait()

print(4)

sleep(2)

conv.notify()

conv.wait()

print(6)

sleep(2)

conv.notify()

conv.wait()

print(8)

thread_01 = Thread(target=target1, args=())

thread_02 = Thread(target=target2, args=())

thread_01.start()

thread_02.start()

这段代码执行的时候,会连续打印1-8,这就是两个线程间同步的更加精准的控制手段。两个线程都是在wait的时候释放lock,此时notify已经发出,那个wait的线程继续执行。

学习到这里,我有个疑问,如果两个线程这么来来回回的传递lock,第3个线程会不会饿死?于是,我写了下面的测试代码。

from time import sleep

from threading import Thread, Lock, Condition

mutex = Lock()

conv = Condition(mutex)

def target1():

with conv:

print(1)

sleep(2)

conv.notify()

conv.wait()

print(3)

sleep(2)

conv.notify()

conv.wait()

print(5)

sleep(2)

conv.notify()

conv.wait()

print(7)

conv.notify()

def target2():

with conv:

print(2)

sleep(2)

conv.notify()

conv.wait()

print(4)

sleep(2)

conv.notify()

conv.wait()

print(6)

sleep(2)

conv.notify()

conv.wait()

print(8)

def target3():

for i in range(4):

with mutex:

print('what...')

sleep(2)

thread_01 = Thread(target=target1, args=())

thread_02 = Thread(target=target2, args=())

thread_03 = Thread(target=target3, args=())

thread_01.start()

thread_02.start()

thread_03.start()

看来,线程饿死的情况是不会发生的,python线程间的调度策略,依然会保证上面代码中target3的调度。从测试情况看,线程target3的调度有随机性,但是target1和target2相互间的执行顺序是严格控制的。

不过,个人感觉使用Condition对象操作线程间的执行,还是很容易出现dead wait的情况。多线程代码还是需要精心调试的,比如上面的测试代码,如果把3个线程的start顺序交换一下,就会出现dead wait:

thread_02.start()

thread_01.start()

thread_03.start()

先打印2,然后1......,最后打印出8后,代码没有notify,target1线程就出现了dead wait。

最后,with conv这行代码,其实效果跟wait很相似,某一个线程wait后,另一个线程才能执行完with conv这行代码,进入内部block执行。

在多线程编程时,越是强大的东西,代码越要小心...

-- EOF --

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值