代码之家  ›  专栏  ›  技术社区  ›  Kostas Oreopoulos

在多处理中作为参数传递锁。为什么有效?

  •  0
  • Kostas Oreopoulos  · 技术社区  · 7 年前

    在下面的代码片段中,我通过打印锁对象的地址看到,每个进程都会获得锁对象的一个副本。

    """ Processes and Locks """
    
    import multiprocessing as mp
    import logging
    
    
    logging.basicConfig(level=logging.DEBUG,
                        format='(%(processName)-10s) (%(threadName)-9s) %(message)s',)
    
    
    def increase_value(iterations, value, lock):
        """Increase a shared variable"""
        print(hex(id(lock)))
        for _ in range(iterations):
            lock.acquire()
            value.value = value.value + 1
            lock.release()
    
    
    def decrease_value(iterations, value, lock):
        """Decrease a shared variable"""
        print(hex(id(lock)))
        for _ in range(iterations):
            lock.acquire()
            value.value -= 1
            lock.release()
    
    
    if __name__ == "__main__":
        ITERATIONS = 100000
        SHARED_VALUE = mp.Value('i', 0)
        LOCK = mp.Lock()
        print(hex(id(LOCK)))
        t1 = mp.Process(target=increase_value, 
                        args=(ITERATIONS, SHARED_VALUE, LOCK))
        t2 = mp.Process(target=decrease_value, 
                        args=(ITERATIONS, SHARED_VALUE, LOCK))
    
        t1.start()
        t2.start()
    
        t1.join()
        t2.join()
    
        logging.debug("SHARED VALUE %d", SHARED_VALUE.value)
    

    为什么会这样?锁如果它们引用相同的锁,则acquire应该有意义。我错过了什么?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Blender    7 年前

    lock.acquire 如果它们指的是同一个锁,那么应该有意义

    它们引用的是同一个锁,而不是同一个Python对象(无论跨Python进程意味着什么)。

    假设您有一把设计非常糟糕的锁:

    import os
    import time
    
    class VeryDumbLock:
        def __init__(self, filename):
            self.filename = filename
    
        def acquire(self):
            while os.path.exists(self.filename):
                time.sleep(0.1)
    
            with open(self.filename, 'w'):
                pass
    
        def release(self):
            os.remove(self, self.filename)
    

    如果您创建 foo = VeryDumbLock('/tmp/lock') bar = VeryDumbLock('/tmp/lock') 在两个不同的进程中,它们实际上都是相同的锁,即使它们显然是驻留在内存中不同地址的不同对象。

    锁定对象在后台实现的实际机制是您唯一需要关心的。