前言

  • 测试环境
Windows 10Python 3.8.2loguru 0.5.3
  • Python 3.8 多过程官网文档: https://docs.python.org/3.8/l...
  • loguru 0.5.3 不是多过程平安的,正好能够用来做多过程与锁的测试
  • 参考文章: Python sharing a lock between processes

代码与阐明

无锁多过程

  • 代码
# encoding: utf-8# author: qbit# date: 2021-01-14# summary: 无锁多过程测试from multiprocessing import Poolfrom loguru import loggerdef ProcOne(ch):    logger.info(ch*20)    return chdef Main():    line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'    with Pool(4) as p:        results = p.map(func=ProcOne, iterable=line)        print(repr(results))if __name__ == "__main__":    Main()
  • 运行后果(乱)

multiprocessing.Lock

  • 代码
# encoding: utf-8# author: qbit# date: 2021-01-14# summary: multiprocessing.Lock 测试import osfrom multiprocessing import Pool, Lockfrom functools import partialfrom loguru import loggerdef ProcOne(lock, ch):    with lock:        logger.info(f'{os.getpid()}-{id(lock)}-{ch*20}')    return chdef Main():    line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'    lock = Lock()    func = partial(ProcOne, lock)    with Pool(4) as p:        results = p.map(func=func, iterable=line)        print(repr(results))if __name__ == "__main__":    Main()
  • 运行后果(报错)

  • 报错的原始是 multiprocessing.Lock 不能被序列化(pickle)

multiprocessing.Manager

  • 代码
# encoding: utf-8# author: qbit# date: 2021-01-14# summary: multiprocessing.Manager 测试import osfrom multiprocessing import Pool, Managerfrom functools import partialfrom loguru import loggerdef ProcOne(lock, ch):    with lock:        logger.info(f'{os.getpid()}-{id(lock)}-{ch*20}')    return chdef Main():    line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'    lock = Manager().Lock()    func = partial(ProcOne, lock)    with Pool(4) as p:        results = p.map(func=func, iterable=line)        print(repr(results))if __name__ == "__main__":    Main()
  • 运行后果(工整)

  • 从图中能够看到,锁的对象 id 在不同的过程中是不同的

multiprocessing.Lock 改进版

  • 代码
# encoding: utf-8# author: qbit# date: 2021-01-14# summary: multiprocessing.Lock 改良测试import osfrom multiprocessing import Pool, Lockfrom loguru import loggerdef ProcOne(ch):    with glock:        logger.info(f'{os.getpid()}-{id(glock)}-{ch*20}')    return chdef init(lock: Lock):    global glock    glock = lockdef Main():    line = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'    lock = Lock()    with Pool(4, initializer=init, initargs=(lock,)) as p:        results = p.map(func=ProcOne, iterable=line)        print(repr(results))if __name__ == "__main__":    Main()
  • 运行后果(工整)

  • 从图中能够看到,锁的对象 id 在不同的过程中还是不同,但从运行后果来看 lock 对象是同一个
  • 如果简略的将 lock 申明为全局对象在 Windows 下并不可行,因为 Windows 不反对 fork,每个过程将会失去不同的 lock 对象
  • 实测在 Linux 中对象 id 雷同
本文出自 qbit snap