Python 生成进程时,锁是否具有不同的id?

Python 生成进程时,锁是否具有不同的id?,python,multiprocessing,locking,spawn,Python,Multiprocessing,Locking,Spawn,我想知道锁在引擎盖下是怎么工作的。我在MacOS上运行这段代码,MacOS使用“spawn”作为启动新进程的默认方法 from multiprocessing import Process, Lock, set_start_method from time import sleep def f(lock, i): lock.acquire() print(id(lock)) try: print('hello world', i) sl

我想知道锁在引擎盖下是怎么工作的。我在MacOS上运行这段代码,MacOS使用“spawn”作为启动新进程的默认方法

from multiprocessing import Process, Lock, set_start_method
from time import sleep


def f(lock, i):
    lock.acquire()
    print(id(lock))
    try:
        print('hello world', i)
        sleep(3)
    finally:
        lock.release()

if __name__ == '__main__':
    # set_start_method("fork")
    lock = Lock()
    for num in range(3):
        p = Process(target=f, args=(lock, num))
        p.start()
        p.join()
输出:

140580736370432
hello world 0
140251759281920
hello world 1
140398066042624
hello world 2
锁在我的代码中起作用。然而,锁的ID让我感到困惑。既然
id
是不同的,那么它们仍然是同一个锁还是有多个锁,并且它们以某种方式秘密通信?
id()
是否仍然在多处理中占有一席之地,我引用“CPython实现细节:id是内存中对象的地址”


如果我使用“fork”方法,
set\u start\u方法(“fork”)
,它会打印出完全相同的
id
,这对我来说完全有意义。

id
被实现为给定对象的内存位置,但不是必需的。使用fork时,单独的进程在修改某些内容(写时复制)之前不会获得自己的内存空间,因此内存位置不会更改,因为它“是”同一个对象。使用spawn时,将创建一个完整的新进程,并将uuu main_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。然后,python在进程(管道)之间创建一个连接,它可以在其中发送要调用的函数,以及要使用的参数。通过此管道的所有东西必须是
pickle
'd,然后取消
pickle
'd。在取消pickle时,通过向操作系统请求具有特定名称的锁(该名称是在创建锁时在父进程中创建的,然后使用pickle发送该名称),可以重新创建特定的锁。这是两个锁的同步方式,因为它由操作系统控制的对象支持。Python然后将这个锁和其他一些数据(原样)存储在新进程的内存中。现在调用
id
将获得此结构的位置,该位置不同,因为它是由不同内存块中的不同进程创建的

下面是一个快速示例,可以让您确信“生成”锁仍然是同步的:

from multiprocessing import Process, Lock, set_start_method

def foo(lock):
    with lock:
        print(f'child process lock id: {id(lock)}')

if __name__ ==  "__main__":
    set_start_method("spawn")
    lock = Lock()
    print(f'parent process lock id: {id(lock)}')
    lock.acquire() #lock the lock so child has to wait
    p = Process(target=foo, args=(lock,))
    p.start()
    input('press enter to unlock the lock')
    lock.release()
    p.join()

不同的“id”是不同的PyObject位置,但与底层互斥体几乎没有关系。我不知道有什么直接的方法可以检查操作系统管理的底层锁。

请仔细检查我是否理解您的答案:通过使用spawn,每个进程都有自己的PyObject,这会导致不同的id。这些不同的PyObject由同一OS托管对象支持。我理解正确吗?@KeZhang基本上是的。在*nix上的底层系统调用是,在windows上的底层系统调用是。两者都有创建新互斥体或按名称打开现有互斥体的选项。调用
id(Lock())
时得到的
PyObject
是“Lib/multipolicessing/synchronize.py”中的
Lock
类的实例。底层信号量是
Lock()。\u semlock
属性上的操作系统“句柄”,该属性在中定义。不幸的是,如果子进程必须通过名称(使用spawn)请求相同对象的新句柄,句柄id将不同,并且只有操作系统知道它是相同的底层锁。