【发布时间】:2015-10-30 11:42:31
【问题描述】:
对于类似supervisor的项目,我使用线程库来管理 一些子进程。在某些时候,用户可以提示命令发送 进程管理线程的指令。这些命令存储在 主进程和进程管理线程之间共享的队列对象。 我想我需要互斥锁来解决并发问题所以我做了一点 脚本尝试一下,但首先没有互斥锁以确保我得到预期 并发问题。
我希望脚本每秒打印一个凌乱的 int 列表:
import threading
import time
def longer(l, mutex=None):
while 1:
last_val = l[-1]
l.append(last_val + 1)
time.sleep(1)
return
dalist = [0]
t = threading.Thread(target=longer, args=(dalist,))
t.daemon = True
t.start()
while 1:
last_val = dalist[-1]
dalist.append(last_val + 1)
print dalist
time.sleep(1)
但实际上它会打印一个很好的如下 int 列表:
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4, 5, 6]
来自this 在另一篇文章中的回答我认为它来自线程库,所以我对多处理库做了同样的事情:
import multiprocessing as mp
import time
def longer(l, mutex=None):
while 1:
last_val = l[-1]
l.append(last_val + 1)
time.sleep(1)
return
dalist = [0]
t = mp.Process(target=longer, args=(dalist,))
t.start()
while 1:
last_val = dalist[-1]
dalist.append(last_val + 1)
print dalist
time.sleep(1)
但我得到了相同的结果,有点“慢”:
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
所以我想知道我真的需要互斥锁来管理类似队列的对象 线程之间共享??? 而且,从上面的代码之一,我怎样才能有效地重现 我搜索的预期并发问题?
感谢阅读
编辑 1: 根据user4815162342 的评论,我更改了第一个 sn-p,并通过在值检索和列表附加之间的“更长”函数中移动睡眠调用来设法获得某种竞争条件:
import threading
import time
def longer(l, mutex=None):
while 1:
last_val = l[-1]
time.sleep(1)
l.append(last_val + 1)
return
dalist = [0]
t = threading.Thread(target=longer, args=(dalist,))
t.daemon = True
t.start()
while 1:
last_val = dalist[-1]
dalist.append(last_val + 1)
print dalist
time.sleep(1)
这给了我这样的东西:
[0, 1]
[0, 1, 1, 2]
[0, 1, 1, 2, 2, 3]
[0, 1, 1, 2, 2, 3, 3, 4]
我设法使用这样的线程锁解决了我的人为问题:
import threading
import time
def longer(l, mutex=None):
while 1:
if mutex is not None:
mutex.acquire()
last_val = l[-1]
time.sleep(1)
l.append(last_val + 1)
if mutex is not None:
mutex.release()
return
dalist = [0]
mutex = threading.Lock()
t = threading.Thread(target=longer, args=(dalist, mutex))
t.daemon = True
t.start()
while 1:
if mutex is not None:
mutex.acquire()
last_val = dalist[-1]
dalist.append(last_val + 1)
if mutex is not None:
mutex.release()
print dalist
time.sleep(1)
然后产生:
[0, 1, 2]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
【问题讨论】:
-
请注意,获取和释放互斥锁的惯用方式是使用
with语句,而不是显式调用acquire和release方法。此外,很少需要将互斥锁传递给函数 - 保护全局资源的互斥锁将驻留在全局变量中,而保护对象级资源的互斥锁将驻留在对象中并且可以通过self.some_attribute访问。跨度> -
感谢您提供的附加信息 :) 我来自 C 编程,我了解到全局变量是坏习惯(安全问题、代码清洁等),你知道全局变量是否是一个特别关注的问题在 Python 中?
标签: python multithreading concurrency