Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。
除了上面画的acquire方法、 release方法、notify方法、wait方法外还有notifyAll方法,不过notifyAll方法不常用。
51cto博客上我看到一篇博文中,形象的以二人对话 (生产者-消费者模)来解释上面的具体理论。
其中空格哥对应原理图中的A函数 ,西米对应的B 函数,每句话是doing操作,空格哥未“doing” 前,西米需要一直等待。最后,你来我往,直到最后都release掉,对话结束。由于代码太长,我给个精简版的,模拟上面的对话:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
#coding:utf-8
#---- Condition
#---- 捉迷藏的游戏
import
threading
,
time
class
Hider
(
threading
.
Thread
)
:
def
__init__
(
self
,
cond
,
name
)
:
super
(
Hider
,
self
)
.
__init__
(
)
self
.
cond
=
cond
self
.
name
=
name
def
run
(
self
)
:
time
.
sleep
(
1
)
#确保先运行Seeker中的方法
self
.
cond
.
acquire
(
)
#b
print
self
.
name
+
': 我已经把眼睛蒙上了'
self
.
cond
.
notify
(
)
self
.
cond
.
wait
(
)
#c
#f
print
self
.
name
+
': 我找到你了 ~_~'
self
.
cond
.
notify
(
)
self
.
cond
.
release
(
)
#g
print
self
.
name
+
': 我赢了'
#h
class
Seeker
(
threading
.
Thread
)
:
def
__init__
(
self
,
cond
,
name
)
:
super
(
Seeker
,
self
)
.
__init__
(
)
self
.
cond
=
cond
self
.
name
=
name
def
run
(
self
)
:
self
.
cond
.
acquire
(
)
self
.
cond
.
wait
(
)
#a #释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。
#d
print
self
.
name
+
': 我已经藏好了,你快来找我吧'
self
.
cond
.
notify
(
)
self
.
cond
.
wait
(
)
#e
#h
self
.
cond
.
release
(
)
print
self
.
name
+
': 被你找到了,哎~~~'
cond
=
threading
.
Condition
(
)
seeker
=
Seeker
(
cond
,
'seeker'
)
hider
=
Hider
(
cond
,
'hider'
)
seeker
.
start
(
)
hider
.
start
(
)
|
执行结果如下:
1
2
3
4
5
6
|
[
root
@
361way
condition
]
# python con3.py
hider
:
我已经把眼睛蒙上了
seeker
:
我已经藏好了,你快来找我吧
hider
:
我找到你了
~
_
~
seeker
:
被你找到了,哎
~
~
~
hider
:
我赢了
|
便于对比,这里再给一个无限循环的例子。经典的生产者与消费者问题:假设有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。生产者的”策略“是如果市场上剩余的产品少于1000个,那么就生产100个产品放到市场上;而消费者的”策略“是如果市场上剩余产品的数量多余100个,那么就消费3个产品。
用Condition解决生产者与消费者问题的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import
threading
import
time
class
Producer
(
threading
.
Thread
)
:
def
run
(
self
)
:
global
count
while
True
:
if
con
.
acquire
(
)
:
if
count
>
1000
:
con
.
wait
(
)
else
:
count
=
count
+
100
msg
=
self
.
name
+
' produce 100, count='
+
str
(
count
)
print
msg
con
.
notify
(
)
con
.
release
(
)
time
.
sleep
(
1
)
class
Consumer
(
threading
.
Thread
)
:
def
run
(
self
)
:
global
count
while
True
:
if
con
.
acquire
(
)
:
if
count
|