在这个信号量示例中,是否需要锁定refill()和buy()?
书中说: 当虚拟售货员的所有者执行refill()函数时 机器来添加一个项目到库存。整个例程 代表一个关键部分;这就是为什么获取锁是唯一的方法 执行所有行。但我认为没有必要锁定refill()和buy() 你的意见怎么样?
#!/usr/bin/env python
from atexit import register
from random import randrange
from threading import BoundedSemaphore, Lock, Thread
from time import sleep, ctime
lock = Lock()
MAX = 5
candytray = BoundedSemaphore(MAX)
def refill():
# lock.acquire()
try:
candytray.release()
except ValueError:
pass
#lock.release()
def buy():
#lock.acquire()
candytray.acquire(False)
#lock.release()
def producer(loops):
for i in range(loops):
refill()
sleep(randrange(3))
def consumer(loops):
for i in range(loops):
buy()
sleep(randrange(3))
def _main():
print('starting at:', ctime())
nloops = randrange(2, 6)
print('THE CANDY MACHINE (full with %d bars)!' % MAX)
Thread(target=consumer, args=(randrange(nloops, nloops+MAX+2),)).start() # buyer
Thread(target=producer, args=(nloops,)).start() # vendor
@register
def _atexit():
print('all DONE at:', ctime())
if __name__ == '__main__':
_main()
答案 0 :(得分:1)
锁是绝对必要的。如果您稍微更改代码以打印每个生产者/消费者呼叫后留下的糖果数量,这可能会有所帮助。替换了信号量,因为它所做的只是保持计数。
我添加了
numcandies = 5
补充:
def refill():
global numcandies
numcandies += 1
print ("Refill: %d left" % numcandies)
购买:
def buy():
global numcandies
numcandies -= 1
print("Buy: %d left" %numcandies)
这是没有锁的输出(显示数据争用问题)。
('starting at:', 'Tue Mar 26 23:09:41 2013')
THE CANDY MACHINE (full with 5 bars)!
Buy: 4 left
Refill: 5 left
Refill: 6 left
Buy: 5 left
Buy: 4 left
Buy: 3 left
Refill: 6 left
Refill: 7 left
Buy: 6 left
('all DONE at:', 'Tue Mar 26 23:09:43 2013')
在producer
的调用与numcandies
计数器的实际更新之间的某处,我们连续2次调用consumer
。
如果没有锁定,则无法控制实际修改计数器的人的顺序。因此,在上述情况下,即使numcandies
更新为3买consumer
,producer
仍然有5的本地副本。更新后,它将计数器设置为6,这是完全错了。
答案 1 :(得分:0)
当然这是关键部分 - 你必须锁定它。取消注释这些注释行。
candytray
是线程挣扎的资源。有关任务独立性的规则:如果两个任务不具有相同的密码域且第一个域不是EQUALS第二个密码域而第二个域是NOT EQUALS第一个密码域,则它们是独立的。这意味着,两个任务只能从一个内存/变量/等中读取。
在你的情况下,如果将candytray
实现为某个队列,则不需要锁定,因为“writer”将数据放在左边,而“reader”从右侧读取。因此,他们的域和codomain不相等,任务是独立的。
但是,如果它不是队列,如果它是一些,让我们说堆,那么作家的codomain干扰读者的域。他们依赖于你,你需要锁定。
正如你所看到的,我从理论方面谈论,而不是Python的方面。但我猜你想要那个。
答案 2 :(得分:0)
来自Wesley Chun的书核心Python应用程序编程的original code看起来像这样:
def refill():
lock.acquire()
print 'Refilling candy...',
try:
candytray.release()
except ValueError:
print 'full, skipping'
else:
print 'OK'
lock.release()
def buy():
lock.acquire()
print 'Buying candy...',
if candytray.acquire(False):
print 'OK'
else:
print 'empty, skipping'
lock.release()
没有lock
,print语句可以交织成难以理解的输出。例如,假设糖果托盘已满。然后假设有一个refill
的调用,然后调用buy
,这样代码行按此顺序执行(没有锁定):
print 'Refilling candy...',
print 'Buying candy...',
try:
candytray.release()
if candytray.acquire(False):
print 'OK'
except ValueError:
print 'full, skipping'
输出如下:
# we start with 5 candy bars (full tray)
Refilling candy... # oops... tray is full
Buying candy...
OK # So now there are 4 candy bars
full, skipping # huh?
这没有意义,所以需要锁定。