前言

  • 测试环境
Windows 10
Python 3.8.2
loguru 0.5.3

代码与说明

无锁多进程

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

image.png

multiprocessing.Lock

  • 代码
# encoding: utf-8
# author: qbit
# date: 2021-01-14
# summary: multiprocessing.Lock 测试
import os
from multiprocessing import Pool, Lock
from functools import partial
from loguru import logger
def ProcOne(lock, ch):
    with lock:
        logger.info(f'{os.getpid()}-{id(lock)}-{ch*20}')
    return ch
def 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()
  • 运行结果(报错)

image.png

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

multiprocessing.Manager

  • 代码
# encoding: utf-8
# author: qbit
# date: 2021-01-14
# summary: multiprocessing.Manager 测试
import os
from multiprocessing import Pool, Manager
from functools import partial
from loguru import logger
def ProcOne(lock, ch):
    with lock:
        logger.info(f'{os.getpid()}-{id(lock)}-{ch*20}')
    return ch
def 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()
  • 运行结果(工整)

image.png

  • 从图中可以看到,锁的对象 id 在不同的进程中是不同的

multiprocessing.Lock 改进版

  • 代码
# encoding: utf-8
# author: qbit
# date: 2021-01-14
# summary: multiprocessing.Lock 改进测试
import os
from multiprocessing import Pool, Lock
from loguru import logger
def ProcOne(ch):
    with glock:
        logger.info(f'{os.getpid()}-{id(glock)}-{ch*20}')
    return ch
def init(lock: Lock):
    global glock
    glock = lock
def 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()
  • 运行结果(工整)

image.png

  • 从图中可以看到,锁的对象 id 在不同的进程中还是不同,但从运行结果来看 lock 对象是同一个
  • 如果简单的将 lock 声明为全局对象在 Windows 下并不可行,因为 Windows 不支持 fork,每个进程将会得到不同的 lock 对象
  • 实测在 Linux 中对象 id 相同
本文出自 qbit snap

qbit
268 声望279 粉丝

引用和评论

0 条评论