可序列化类型和多进程 PicklingError

遇到一个报错:

PicklingError: Can't pickle <type'instancemethod'>: attribute lookup __builtin__.instancemethod failed

当时的情况是想写一个多进程的解析代码,爬虫爬到的内容给扔过来就不管了,差不多这个意思:

# !/usr/bin/env python
# -*- coding: utf-8 -*-

from concurrent.futures import ProcessPoolExecutor


class PageProcess(object):
    def __init__(self, worker):
        self.max_worker = worker

    def single_process(self, page):
        pass

    def multi_process(self, page_list):
        with ProcessPoolExecutor(max_workers=self.max_worker) as pp:
            result = pp.map(self.single_process, page_list)

这个错误是这么造成的:

  1. 在类中使用进程池;
  2. 进程池使用 Queue 管理任务队列;
  3. Queue 要求传递的内容必须都是可以被序列化的;

那么问题来了,哪些类型是可以被序列化的呢?

根据 官方文档,可序列化的类型包括:

类型 原文
布尔型和空值 None, True, and False
数字类型中的整数,浮点数和复数 integers, floating point numbers, complex numbers
字符串类型和二进制类型 (字节流,字节数组) strings, bytes, bytearrays
只包含可序列化对象的元组、集合、列表、字典 tuples, lists, sets, and dictionaries containing only picklable objects1
模块中最顶层声明的非匿名函数 functions defined at the top level of a module (using def, not lambda)
模块中最顶层声明的内置函数 built-in functions defined at the top level of a module
模块中最顶层声明的类 classes that are defined at the top level of a module
__getstate__ 的结果或 __dict__ 是可序列化的这样的类的实例 instances of such classes whose __dict__ or the result of calling __getstate__() is picklable

破案了,上面代码中,我们的进程池要序列化的是类中的函数,就不符合最顶层定义的函数的要求。

所以最直接的解决办法也很简单,把要并行的函数抽外面去就行了:

# !/usr/bin/env python
# -*- coding: utf-8 -*-

from concurrent.futures import ProcessPoolExecutor


def single_process(page):
    pass


class PageProcess(object):
    def __init__(self, worker):
        self.max_worker = worker

    def multi_process(self, page_list):
        with ProcessPoolExecutor(max_workers=self.max_worker) as pp:
            result = pp.map(single_process, page_list)


  1. 英文这种语序 / 标点我老是搞不懂,这个 containing only picklable objects 到底是指 dictionaries 还是前面全部,就当是全部吧 ↩︎

Lex Wayne
Lex Wayne
Python Knight & Go Padawan

You see, madness, as you know, is like gravity.