Python multiprocessing 打印报错信息和解决进程不运行的问题
multiprocessing 的使用
multiprocessing的基本用法如下
from multiprocessing import Pool
# 你自定义的需要反复调用的用于并行计算的进程
def your_func(your_data):
do_something()
if __name__ == '__main__':
# 定义数量为20的进程池
process_pool = Pool(20)
# 从你的数据list中取出数据,作为你的自定义函数的参数,加入进程池
for your_data in your_list:
process_pool.apply_async(your_func, (your_data,))
process_pool.close()
process_pool.join()
需要注意的是进程创建部分的代码必须放在__main__ 函数中,不然,新建的函数会拷贝加载程序文件,除了__main__之外的全局的代码片段会被执行一遍,就导致了子进程也会创建进程池,也会创建子进程,就陷入了无限的子进程创建的循环中,耗尽系统的资源
但是,我在我自己项目中使用该方法的时候,发现your_func并没有执行,控制台也没报错
打印报错信息
- 可以使用如下的方式,增加 print_error 回调函数 打印报错信息
from multiprocessing import Pool
# 你自定义的error_callback函数
def print_error(value):
print("error: ", value)
# 你自定义的需要反复调用的用于并行计算的进程
def your_func(your_data):
do_something()
if __name__ == '__main__':
# 定义数量为20的进程池
process_pool = Pool(20)
# 从你的数据list中取出数据,作为你的自定义函数的参数,加入进程池
for your_data in your_list:
process_pool.apply_async(your_func, (your_data,), error_callback=print_error)
# 如上,设置error_callback=自定义的打印错误的函数!!!
process_pool.close()
process_pool.join()
上面这种方式只能打印错误信息,不能打印错误堆栈信息。代码如果过长的话,很难定位到出错的代码片段。 2. 可以使用traceback 打印堆栈信息
from multiprocessing import Pool
import multiprocessing
import traceback
def error(msg, *args):
return multiprocessing.get_logger().error(msg, *args)
class LogExceptions(object):
def __init__(self, callable):
self.__callable = callable
return
def __call__(self, *args, **kwargs):
try:
result = self.__callable(*args, **kwargs)
except Exception as e:
# Here we add some debugging help. If multiprocessing's
# debugging is on, it will arrange to log the traceback
error(traceback.format_exc())
# Re-raise the original exception so the Pool worker can
# clean up
raise
# It was fine, give a normal answer
return result
pass
if __name__ == '__main__':
multiprocessing.log_to_stderr() # 加上此行
process_pool = Pool(20)
# 你自定义的需要反复调用的用于并行计算的进程
def your_func(your_data):
do_something()
# 从你的数据list中取出数据,作为你的自定义函数的参数,加入进程池
for your_data in your_list:
process_pool.apply_async(LogExceptions(your_func), (your_data,)) # 套上LogExceptions
process_pool.close()
process_pool.join()
进程不运行的问题
我代码的问题
from multiprocessing import Pool
# 你自定义的需要反复调用的用于并行计算的进程
class MyClass:
def __init__(self, sqliteSql):
self.sqliteSql = sqliteSql
def run(self, data):
# do some thing
pass
if __name__ == '__main__':
# 定义数量为20的进程池
process_pool = Pool(20)
sqliteSql = SqliteSql() # 我自己封装的一个基于sqlalchemy的对sqlite3访问的类,维护了数据库访问的session等信息。
myObj = MyClass(sqliteSql)
# 从你的数据list中取出数据,作为你的自定义函数的参数,加入进程池
for your_data in your_list:
process_pool.apply_async(myObj.run, (your_data,), error_callback=print_error)
process_pool.close()
process_pool.join()
上述代码报错
error: Can't pickle local object 'create_engine.<locals>.connect'
我猜测是因为myObject对象的成员 sqliteSql中包含一些无法使用pickle序列化的对象。无法使用pickle序列化,在创建新的进程的时候,就无法对内存中的内容进行拷贝,导致进程创建失败。
解决方法。我的解决方法比较笨。就是不在myObj的成员中保存sqliteSql对象。在run 函数中创建一个sqliteSql 对象。这样拷贝myObject进行进程创建的时候,就不涉及sqliteSql的拷贝工作。 代码如下:
from multiprocessing import Pool
# 你自定义的需要反复调用的用于并行计算的进程
class MyClass:
def __init__(self):
pass
def run(self, data):
sqliteSql = SqliteSql()
# do some thing
pass