这一切都取决于如何multiprocessing
实施RLock
。我知道多处理可以跨主机工作,这意味着同步原语可以跨套接字工作。如果这是真的,它会引入很多(可变)延迟。
所以我做了一个实验。
RLock
这是一个被多个进程使用的例子(以防止所有锁都在同一个进程中的任何快速路径):
#!/usr/bin/env python
import multiprocessing
from time import sleep
lock = multiprocessing.RLock()
def noop(myname):
# nonlocal lock
sleep(0.5)
print myname, "acquiring lock"
with lock:
print myname, "has lock"
sleep(0.5)
print myname, "released lock"
sProc1 = multiprocessing.Process(target=noop, args=('alice',))
sProc2 = multiprocessing.Process(target=noop, args=('bob',))
sProc1.start()
sProc2.start()
sProc1.join()
sProc2.join()
当它运行时,它的输出看起来像这样:
alice acquiring lock
alice has lock
bob acquiring lock
alice released lock
bob has lock
bob released lock
太好了,现在通过strace使用系统调用跟踪运行它。
在下面的命令中,该-ff
选项告诉工具“跟踪fork()
”调用,即跟踪由主进程启动的任何进程。为简洁起见,我也在使用-e trace=futex,write
,它根据我在发布之前做出的结论过滤输出。通常你会在没有-e
选项的情况下运行并使用文本编辑器 /grep
来探索事后发生的事情。
# strace -ff -e trace=futex,write ./traceme.py
futex(0x7fffeafe29bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 7fb92ac6c700) = -1 EAGAIN (Resource temporarily unavailable)
futex(0x7fb92a8540b0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x7fb92aa7131c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(3, "\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32) = 32
Process 25873 attached
Process 25874 attached
Process 25872 suspended
[pid 25873] write(1, "alice acquiring lock\n", 21alice acquiring lock
) = 21
[pid 25873] write(1, "alice has lock\n", 15alice has lock
) = 15
[pid 25874] write(1, "bob acquiring lock\n", 19bob acquiring lock
) = 19
[pid 25874] futex(0x7fb92ac91000, FUTEX_WAIT, 0, NULL <unfinished ...>
[pid 25873] futex(0x7fb92ac91000, FUTEX_WAKE, 1 <unfinished ...>
[pid 25874] <... futex resumed> ) = 0
[pid 25873] <... futex resumed> ) = 1
[pid 25874] write(1, "bob has lock\n", 13 <unfinished ...>
bob has lock
[pid 25873] write(1, "alice released lock\n", 20 <unfinished ...>
alice released lock
[pid 25874] <... write resumed> ) = 13
[pid 25873] <... write resumed> ) = 20
Process 25872 resumed
Process 25873 detached
[pid 25872] --- SIGCHLD (Child exited) @ 0 (0) ---
Process 25872 suspended
[pid 25874] write(1, "bob released lock\n", 18bob released lock
) = 18
Process 25872 resumed
Process 25874 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
从 print ( write()
) 消息和调用哪个阻塞和稍后恢复的模式来看,使用或“Fast Userspace Mutex”实现futex
似乎很清楚。顾名思义,这是同步的不错选择。RLock
futex
当一个进程在系统调用futex
中被阻塞时,例如该进程出于所有意图和目的而阻塞 I/O。
所有这一切都意味着它multiprocessing.RLock
是高效的,并且按照它的设计目的去做。因此,如果您的应用程序在使用同步时的性能低于您的预期,那么您的算法很可能是罪魁祸首。