当我学习使用SyncManager在多个进程之间共享公共对象时,我注意到Thread在SyncManager的上下文中工作的奇怪行为。
据我了解,SyncManager创建一个服务器进程,接受来自其他进程的连接,然后使用Thread调用目标方法。(https://github.com/python/cpython/blob/master/Lib/multiprocessing/managers.py#L184)
但是,在下面的示例代码中,通过调用获得的线程 idthreading.get_ident()
结果是相同的值。
我添加了被调用方法的RLock版本以及非锁定版本。从我从日志的时间线中可以看出,它的行为符合预期 - 不同的线程调用该cube
方法,但是相同的线程 id 怎么来的?
我了解在最后一个线程终止后,另一个线程中可能会出现相同的线程 ID。但它不能解释没有RLock的行为。
from multiprocessing import Process
from multiprocessing.managers import SyncManager
import time
import os
import logging
import threading
from threading import RLock
class MyManager(SyncManager):
pass
class CommonObj:
def __init__(self):
self.logger = logging.getLogger(
"COMMON-%d-%d" % (os.getpid(), threading.get_ident())
)
self.lock = RLock()
def cube_lock(self, x):
with self.lock:
self.logger.info("lock acquired")
time.sleep(3)
result = x * x * x
self.logger.info("lock released")
return result
def cube(self, x):
self.logger.info("cube called")
time.sleep(3)
result = x * x * x
self.logger.info("cube finish")
return result
def worker(cube):
logger = logging.getLogger("WORKER-%d" % os.getpid())
logger.info("calling common_obj.cube")
result = cube(2)
logger.info("result is %d" % result)
def main():
logging.basicConfig(level=logging.INFO)
MyManager.register("CommonObj", CommonObj)
processes = list()
with MyManager() as manager:
common_obj = manager.CommonObj()
print("Calling cube without RLock:")
for i in range(3):
p = Process(target=worker, args=(common_obj.cube,))
processes.append(p)
p.start()
for p in processes:
p.join()
print("joined %r" % p)
print("\n\nCalling cube with RLock:")
processes.clear()
for i in range(3):
p = Process(target=worker, args=(common_obj.cube_lock,))
processes.append(p)
p.start()
for p in processes:
p.join()
print("joined %r" % p)
if __name__ == "__main__":
main()
Calling cube without RLock:
INFO:WORKER-1389:calling common_obj.cube
INFO:WORKER-1390:calling common_obj.cube
INFO:COMMON-1388-123145579134976:cube called
INFO:COMMON-1388-123145579134976:cube called
INFO:WORKER-1391:calling common_obj.cube
INFO:COMMON-1388-123145579134976:cube called
INFO:COMMON-1388-123145579134976:cube finish
INFO:COMMON-1388-123145579134976:cube finish
INFO:WORKER-1389:result is 8
INFO:COMMON-1388-123145579134976:cube finish
INFO:WORKER-1391:result is 8
INFO:WORKER-1390:result is 8
joined <Process(Process-2, stopped)>
joined <Process(Process-3, stopped)>
joined <Process(Process-4, stopped)>
Calling cube with RLock:
INFO:WORKER-1394:calling common_obj.cube
INFO:COMMON-1388-123145579134976:lock acquired
INFO:WORKER-1395:calling common_obj.cube
INFO:WORKER-1396:calling common_obj.cube
INFO:COMMON-1388-123145579134976:lock released
INFO:COMMON-1388-123145579134976:lock acquired
INFO:WORKER-1394:result is 8
joined <Process(Process-5, stopped)>
INFO:COMMON-1388-123145579134976:lock released
INFO:COMMON-1388-123145579134976:lock acquired
INFO:WORKER-1395:result is 8
joined <Process(Process-6, stopped)>
INFO:COMMON-1388-123145579134976:lock released
INFO:WORKER-1396:result is 8
joined <Process(Process-7, stopped)>