在使用python3.6的多进程的时候,遇到了进程卡死的问题。
具体表现为:多进程不停的开打爆了机器
排查后发现,原因是在使用apply_sync的时候,输入进去的参数大小太大导致的卡死,正常情况下应该是有这样的报错的:
python struct.error: ‘i’ format requires -2147483648 <= number <= 2147483647
原因是在使用pickling传输数据的时候大小太大超过限制爆掉了(这个问题升到3.8就可以解决)
但是由于我在传输数据的时候加入了multiprocessing.manager,加入后反而不会提示这个异常报错了,猜测是manager里加了处理,但是依然没有解决问题,运行的时候发现多进程依然没有正常运行和输出结果。
之后我还尝试了各种方法:
比如使用gc清理无效变量和内存
import gc
del a,b #a,b是占用内存大的变量名
gc.collect()
这么做有用,内存占用量减少但是还是无法正常处理多进程
然后又想到程序里用popen调用了shell命令,会不会是这个问题?在最后补上了清空Pipe的代码
with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as fp:
try:
num = 0
while True:
line = fp.stdout.readline()
cmd_status = fp.poll()
if not line and cmd_status is not None:
break
else:
try:
s1 = str(line, encoding='utf-8')
except: # UrlEncodedFormEntity编码格式默认是iso_8859_1
s1 = str(line, encoding='iso_8859_1')
# 解析数量限制
if num > 5000000 and ' },\n' == s1:
json_str += "}]"
parse_msg.append("1\t" + parse_status['1'] + "\texceed limit 5000000 lines")
break
json_str += s1
except Exception as e:
parse_msg.append("3\t" + parse_status['3'] + "\tread json str error--" + str(e))
finally:
# 清除管道符里的输出并kill掉进程
if fp.stdin:
fp.stdin.close()
if fp.stdout:
fp.stdout.close()
if fp.stderr:
fp.stderr.close()
try:
fp.kill()
except OSError:
pass
还是没用,最后问了chatGPT,说建议使用Process+Queue来处理大量数据
最终解决了,原因应该是Queue使用的是Pipe没有触发pickle的大小限制报错,所以可以正常运行。
def Fun(n,output)
result=1
output.put(result)
all_result_list = []
output = Queue()
thread_list = []
for process_id in range(maxprocess_num):
th = Process(target=Fun, args=(n, output))
thread_list.append(th)
th.start()
for th_item in thread_list:
while th_item.is_alive():
while not output.empty():
all_result_list.append(output.get())
for th_item in thread_list:
th_item.join()
然后又发现,由于在脚本运行途中读取了一个600M的文件,多进程的内存复制机制会导致占用的内存量暴增,这可咋办?
询问chatGPT,提示我使用shared_memory,再一搜脸又黑了:这是python3.8加入的特性,在多进程之间共享内存减少内存占用量
后来查找后发现3.6环境也可以用,就是非常复杂:
https://blog.csdn.net/TracelessLe/article/details/110101588
问题暂时解决了