一.报错TypeError: cannot pickle ‘_io.TextTOWrapper‘ object
在使用多进程时报错,错误信息:TypeError: cannot pickle '_io.TextTOWrapper' object
1.1.原因分析
1.pickle模块是将python中所有的数据结构以及对象转换成bytes类型。
2.多进程对象执行时存在不能被序列化的对象
3.结合代码分析:
初始化对象(创建文件对象) -- 多进程调用对象方法
经排查,文件对象不能被pickle导致,使用logger模块也存在类似问题报:cannot pickle thread_rlock,部分数据库连接实例化对象
1.2.解决
既然文件对象不能在进程调用前被创建,那么试试在进程初始化后再创建文件对象。
经测试,以上方法可行。即当多进程调用对象的方法前,该对象不要有属性指向文件对象(等不能被pickle的对象),在多进程执行方法过程中再创建需要创建的对象
二.报错信息freeze_support()
首先讲为什么Windows系统中使用多进程不加if name == 'main’会报错,这主要是因为python创建子进程的时候相当于会开辟新的一块内存空间去存储主进程中的代码,并且是通过导包的形式去复刻主进程中的代码的,那么这里就会有一个问题,如果不加if __name__ == '__main__':这个判断的话,那么执行代码的时候就会无限递归的创建子进程,但是multiprocessing.Process的源码中对无限递归的创建子进程这种行为是不允许的,所以就出现了报错提示,因此在windows系统中执行上面代码的时候就需要将创建子进程的代码放在if __name__ == '__main__':这个判断下,这个时候子进程中通过导包的形式复刻的代码里面if __name__ == '__main__':这个判断会不成立,因为此时的 name 就不是 'main’了,在子进程中下面的代码也就不会被执行,那么最后也就不会报错了。
接着讲一下为什么相同的代码在Linux系统中不加if __name__ == '__main__':的话就不会报错,这是因为在Linux系统中有一个os.fork() 方法,这个方法会fork出一个子进程,在子进程中返回0,在父进程中返回子进程的进程编号,然后它们可以检查调用的返回值确定其状态,然后判断到底是父进程还是子进程,如果判断出是子进程,那么子进程就只继承必要的资源,也就是运行进程对象的目标方法所必须的资源,也就避免了递归的执行创建子进程的代码,所以在Linux系统中即使不加if __name__ == '__main__':也不会报错,而这个方法在window系统中是没有的,这就是以上所有问题的根本原因。