在不同 python 个模块的功能中无法识别锁

Lock is not recognized in functions of different python modules

我有一个多处理锁,我定义为

import multiprocessing

lock1 = mp.Lock()

为了在不同的子进程之间共享这个锁,我这样做:

def setup_process(lock1):
    global lock_1
    lock_1 = lock1

pool = mp.Pool(os.cpu_count() - 1,
               initializer=setup_process,
               initargs=[lock1])

现在我注意到,如果进程调用以下函数,并且该函数定义在同一个 python 模块(即同一个文件)中:

def test_func():
    print("lock_1:", lock_1)
    with lock_1:
        print(str(mp.current_process()) + " has the lock in test function.")

我得到如下输出:

lock_1 <Lock(owner=None)>
<ForkProcess name='ForkPoolWorker-1' parent=82414 started daemon> has the lock in test function.
lock_1 <Lock(owner=None)>
<ForkProcess name='ForkPoolWorker-2' parent=82414 started daemon> has the lock in test function.
lock_1 <Lock(owner=None)>
<ForkProcess name='ForkPoolWorker-3' parent=82414 started daemon> has the lock in test function.

但是,如果 test_function 定义在不同的文件中,则锁无法识别,我得到:

NameError:
name 'lock_1' is not defined

这似乎对每个函数都会发生,其中重要的区别在于该函数是在此模块中定义还是在另一个模块中定义。我确定我在全局变量中遗漏了一些非常明显的东西,但我是新手,我还没弄明白。怎样才能让锁随处可见?

好吧,我今天学到了一些关于 python 的新知识:global 实际上并不是真正的全球性。 It only is accessible at the module scope.

有多种方法可以与模块共享您的锁以允许使用它,文档甚至建议在模块之间使用 "canonical" way of sharing globals(尽管我觉得这不是最多的)适合这种情况)。对我来说,这种情况首先说明了使用全局变量的缺点之一,尽管我不得不承认在 multiprocessing.Pool 初始值设定项的特定情况下,使用全局变量传递似乎是被接受的甚至是预期的用例数据到工作函数。全局变量不能跨越模块边界实际上是有道理的,因为这会使单独的模块 100% 依赖于由特定脚本执行,因此不能真正将其视为单独的独立库。相反,它可以只包含在同一个文件中。我认识到这可能与拆分内容不一致,不是为了创建可重用的库,而只是为了在较短的段中逻辑地组织代码以便阅读,但这显然是 python.[=21 的设计者的风格选择。 =]

要解决你的问题,归根结底,你将不得不将锁作为参数传递给另一个模块,所以你最好让 test_func 接收 lock_1 作为论据。但是您可能已经发现这会导致出现 RuntimeError: Lock objects should only be shared between processes through inheritance 消息,那么该怎么办呢?基本上,我会保留你的初始化程序,并将 test_func 放在 __main__ 范围内的另一个函数中(因此可以访问你的 global lock_1),该函数获取锁,然后传递它到功能。不幸的是,我们不能使用更好看的装饰器或包装器函数,因为那些 return 函数只存在于本地范围内,并且在使用“spawn”作为启动方法时无法导入。

from multiprocessing import Pool, Lock, current_process

def init(l):
    global lock_1
    lock_1 = l

def local_test_func(shared_lock):
    with shared_lock:
        print(f"{current_process()} has the lock in local_test_func")

def local_wrapper():
    global lock_1
    local_test_func(lock_1)

from mymodule import module_test_func #same as local_test_func basically...

def module_wrapper():
    global lock_1
    module_test_func(lock_1)

if __name__ == "__main__":
    l = Lock()
    with Pool(initializer=init, initargs=(l,)) as p:
        p.apply(local_wrapper)
        p.apply(module_wrapper)