虽然这在 docs中并不完全清楚,但多处理同步原语实际上也可以同步线程。
例如,如果您运行以下代码:
import multiprocessing
import sys
import threading
import time
lock = multiprocessing.Lock()
def f(i):
with lock:
for _ in range(10):
sys.stderr.write(i)
time.sleep(1)
t1 = threading.Thread(target=f, args=['1'])
t2 = threading.Thread(target=f, args=['2'])
t1.start()
t2.start()
t1.join()
t2.join()
...输出将始终是1111111111222222222
or 22222222221111111111
,而不是两者的混合。
这些锁是在 Windows 上的 Win32 内核同步对象、支持它们的 POSIX 平台上的信号量之上实现的,而在其他平台上根本没有实现。(您可以使用 进行测试import multiprocessing.semaphore
,这将ImportError
在其他平台上引发 ,如文档中所述。)
话虽如此,拥有两级锁肯定是安全的,只要您始终以正确的顺序使用它们——也就是说,永远不要抓住 .threading.Lock
除非您可以保证您的进程具有multiprocessing.Lock
.
如果你足够聪明地做到这一点,它可以带来性能优势。(Windows 和某些 POSIX 平台上的跨进程锁可能比进程内锁慢几个数量级。)
如果您只是以明显的方式进行(仅with threadlock:
在with processlock:
块内进行),它显然不会提高性能,实际上会减慢一些速度(尽管很可能不足以衡量),并且不会添加任何直接利益。当然你的读者会知道你的代码是正确的,即使他们不知道multiprocessing
锁在线程之间起作用,并且在某些情况下调试进程内死锁可能比调试进程间死锁容易得多......但我不认为其中任何一个在大多数情况下,这是额外复杂性的充分理由。