def fun(produceQueue, key, consumerQueue):
if not produceQueue.empty():
args = produceQueue.get()
else:
raise Exception("produce queue is empty!")
originX, originY, target, num = args[0], args[1], args[2], args[3]
factor_dict = self.model_predict(originX, originY, target, key=key)
consumerQueue.put({key: factor_dict})
consumerQueue.join_thread()
if __name__ == '__main__':
produceQueue = Queue(3)
consumerQueue = Queue(3)
pList = []
for key in range(3):
p = Process(target=fun, args=(produceQueue, key, consumerQueue))
pList.append(p)
p.start()
for p in pList:
p.join() #阻塞主线程
以上是我用python的多线程multiprocessing模块做的测试,主要是创建了三个子线程,用来并行执行业务逻辑以提高效率
我的开发环境是win10 8核 所以没有开启进程池
当用pycharm跑的时候抛出了错误:
TypeError: cannot serialize '_io.BufferedReader' object
Can't pickle attribute *** from ***
通过查阅StackOverflow网上的解释和百度,说的是对象没有序列化,因为进程间是不能通信的,而传的参数可能是主进程的全局变量从而导致报错
但是我的程序是根据队列的形式来进行进程间通信的,按理说不可能存在临界资源异常的问题,于是又往下找原因,一步一步debug,后来在Anaconda3\Lib\multiprocessing\popen_spawn_win32.py代码中发现了端倪
reduction.dump(process_obj, to_child)
这一步语句是指将对象序列化到子进程中,就是这句报错导致程序一直不成功,后来查看源代码,说的是该方法要调用创建进程的fork方法,而windows系统上不支持这样的方法,从而导致报错 晕~~~
后来将整个项目用docker部署好后,上述代码完全可以执行,没有报任何的错,但是却出现了返回的字典的key列表的维数是二维甚至一维的情况,由于是并发执行,说明有进程没有参与工作
参考这篇博客:
https://www.cnblogs.com/bigtreei/p/7988804.html
找到了点启发
原来是qList位主进程中的变量,在做循环join的时候总有主进程快于子进程的时候,而此时没来的及阻塞主进程,程序就退出了,从而消费者队列上面的数据就少了,所以将代码改成
for key in range(3):
p = Process(target=fun, args=(produceQueue, key, consumerQueue))
pList.append(p)
p.start()
p.join() #阻塞主线程
就完全没有问题了,不过牺牲了性能效率,因为每次开启子进程就要去阻塞主进程,仿佛给人的感觉是串行,但是得到的结果是正确的