python multiprocessing 报错cannot pickle ‘_io.TextTOWrapper‘ object

一.报错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系统中是没有的,这就是以上所有问题的根本原因。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误是由于Python中的多线程锁对象(_thread.rlock)无法被序列化(pickled)导致的。在使用pickle模块对对象进行序列化时,如果对象中包含了无法被序列化的对象,就会出现这个错误。解决方法是在序列化之前将多线程锁对象从对象中移除,或者使用其他可序列化的锁对象。 ### 回答2: 问题背景 当前,Python 是最流行的编程语言之一。它以其干净、明晰和用户友好的代码而著称。然而,Python 有许多内置的数据类型,却不支持跨进程共享。进程间通信仍是 Python 编程的交易痛点。为了实现跨进程之间的数据共享,Python 提供了许多方案之一,Pickling和Unpickling方法。Pickling是将数据序列化为Python对象,如 Pandas dataframe 或NumPy array等等。虽然这对于小规模的Python应用程序可以正常工作,但当您开始处理大型数据集或在多核计算机上运行Python应用程序时,Pickling会遇到一些问题。 问题分析 无法决议线程,并发和互斥体问题:Python有一个线程锁对象,即_thread.rlock对象。 这种对象不能被Pickling处理。互斥对象可以在它们的生命周期中进行锁定和解锁操作。当您需要在多个进程之间共享这些对象时,Python会尝试Pickling它们。由于这种锁对象的特殊性质,导致 Python 无法为此类对象提供支持,因此在处理这些对象时,会出现 “cannot pickle '_thread.rlock' object” 的错误。 解决方法 属于 Python 提供了一个 `multiprocessing.Manager` 模块来管理进程共享的对象。当在跨进程之间共享进程锁时,应采用此方法。第一步是创建共享进程锁,第二步是将其发送到管理器模块中,然后可以使用该模块中提供的其他共享对象。 下面是一个处理这个问题的示例代码: ```python from multiprocessing import Process, Manager def some_function(lock: mp.Lock, result: mp.Manager): # Acquire lock here with lock: # ... your code result.put('Result here') if __name__ == '__main__': with Manager() as mngr: lock = mngr.Lock() result = mngr.Queue() processes = [] for i in range(10): p = Process(target=some_function, args=(lock, result)) p.start() processes.append(p) for p in processes: p.join() while not result.empty(): print(result.get()) ``` 上面的代码中,我们使用 `Manager` 模块中的 `Lock()` 来创建进程锁,然后将其传递给我们需要使用的函数中。在函数内部,我们通过使用 `with` 语句构造一个上下文环境,并利用进程锁进行操作。此方法可以使用在多个进程中共享对象的方法,可以更好的解决可能会出现在并发处理过程中的对象共享问题。 总结 “cannot pickle '_thread.rlock' object”错误是由于Python中的进程锁不能被 Pickling 处理造成的。虽然 Python 提供了许多解决方案,但最好的方法是使用 `multiprocessing.Manager` 模块来进行处理。这个模块提供了许多方法来管理多进程控制下的共享数据结构,并且可以有效地避免锁定和其他并发性问题。程序开发人员可以使用上下文管理器来约束锁定,从而确保对象的一致性。尽管解决方案对于初学者来说可能会有点棘手,但一旦熟悉,可以在高效的并发和分布式计算方面发挥巨大的作用。 ### 回答3: 在Python中,pickle是一个用于序列化和反序列化Python对象的标准模块。它可以将Python对象转换成一个序列化的二进制数据流,以便于存储和传输。 在使用pickle时,有时会出现“cannot pickle '_thread.rlock' object”错误。这个错误通常是因为某个对象无法被序列化而导致的。在Python中,一些对象是无法被序列化的,比如线程锁(_thread.rlock)。 线程锁是一种用于控制线程并发访问的工具,它可以保证同一时刻只有一个线程可以访问共享资源。但是,由于线程锁是一个底层的对象,并且与线程密切相关,因此无法被序列化。 当我们尝试将包含线程锁的对象序列化时,就会出现“cannot pickle '_thread.rlock' object”错误。这时需要我们重新设计对象结构,将线程锁从对象中移除,或者使用其他可以被序列化的同步工具替代线程锁,比如信号量(Semaphore)或事件(Event)。 此外,还有一些其他的不能被序列化的对象,比如文件、套接字等等。在使用pickle时,一定要注意哪些对象是可以被序列化的,哪些不可以,以避免出现类似的错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值