使用python多进程(multiprocessing)中遇到的问题

推荐阅读:http://luly.lamost.org/blog/python_multiprocessing.html

1. 参数共享

1.1 进程间传递的所有参数必须是可以被pickle的

  • 可以被pickle的python对象类型:(没找到之前那个链接。。。)
    what can be pickled?
  • 被pickle的对象(比如说其中包含有一棵树)的递归层次有限制,可以用sys.setrecursionlimit(n)来改变,默认的是1000。
  • 包裹在Manager().dict()或者Manager().list()中的对象也必须是可以被pickle的。
  • 当自定义类的对象不能被pickle时,可以利用__getstate__()将其中无法被pickle的属性去掉,同时用__setstate__()在unpickle时找回来,具体参见:https://blog.csdn.net/xuelians/article/details/79999275

1.2 Manager()

可以配合进程池使用,但是注意:Manager().dict()返回的是DictProxy,不是dict。直接遍历其中的元素会出现以下错误:

my_dict = Manager().dict()
for i in my_dict:
	print(i)

# 错误如下:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in __getitem__
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 740, in _callmethod
    raise convert_to_error(kind, result)
KeyError: 2

这是因为DictProxy没有实现iterkeys(),具体解释见http://m.newsmth.net/article/Python/100915。所以可以这么写:

for i in my_dict.keys():
	# ...

1.3 内存共享sharedmem(避免pickle)

共享内存中只能存放numpy数组,而且多维数组我没实践出来。。。参考文档:http://rainwoodman.github.io/sharedmem/

 

2. 多进程打印日志

  • 根据官方文档的介绍,logging 是线程安全的,也就是说,在一个进程内的多个线程同时往同一个文件写日志是安全的。但是多个进程往同一个文件写日志不是安全的
    为了解决这个问题,可以使用 ConcurrentLogHandler,ConcurrentLogHandler 可以在多进程环境下安全的将日志写入到同一个文件,并且可以在日志文件达到特定大小时,分割日志文件。在默认的 logging 模块中,有个 TimedRotatingFileHandler 类,可以按时间分割日志文件,可惜 ConcurrentLogHandler 不支持这种按时间分割日志文件的方式。
    安装:pip install ConcurrentLogHandler
    使用:from cloghandler import ConcurrentRotatingFileHandler
    (以上参考:https://www.cnblogs.com/restran/p/4743840.html)
  • 安装及使用:
    (1)windows下安装时还需要安装pypiwin32。
    (2)使用时出现了进程卡住的情况,查证之后发现是windows下的lock无法正常的获取和释放。
    (3)未解决(2)中问题,可以使用GitHub上一位老哥修复过的package,名为concurrent_log_handler
    安装 pip install concurrent_log_handler
    运行后会自动创建对应的.lock文件,通过锁的方式来安全地写日志文件。
from concurrent_log_handler import ConcurrentRotatingFileHandler

def set_mp_logger(log_file, ch_flag=True, fh_flag=True):
    """
    将logger信息输出到log_file文件中
    :param log_file:
    :return:
    """
    logger = logging.getLogger(os.path.basename(log_file).replace('.log', ''))
    formatter = logging.Formatter(fmt='[%(name)s]: %(asctime)s - %(filename)s - %(levelname)s - %(message)s',
                                  datefmt='%Y-%m-%d %H:%M:%S %A')
    logger.setLevel(logging.DEBUG)

    fh = ConcurrentRotatingFileHandler(log_file, maxBytes=1024*1024, backupCount=2, encoding='utf-8')
    fh.setLevel(logging.INFO)

    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)

    ch.setFormatter(formatter)
    fh.setFormatter(formatter)
    if ch_flag is True:
        logger.addHandler(ch)
    if fh_flag is True:
        logger.addHandler(fh)
    return logger

my_logger = set_mp_logger(os.path.join(const.PROJECT_PATH, 'log', 'my_logger.log'))
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值