mpi4py调用gather收集结构体列表后遍历触发类型错误问题
问题报错
使用mpi4py传输自定义结构体对象列表时,gather收集完成后根进程遍历返回对象触发类型错误,报错信息如下:
Traceback (most recent call last): File "Primary_secondary_co-sim.py", line 509, in <module> sm_clear_all(params, curr_pri_timestep, soln) File "/home/gridsan/jvineet9/vvc_sims/code/sm_clear_all.py", line 162, in sm_clear_all node_num = soln_node['node_num'] TypeError: list indices must be integers or slices, not str Primary job terminated normally, but 1 process returned a non-zero exit code. Per user-direction, the job has been aborted. ----------------------------------------------------------------- mpirun detected that one or more processes exited with non-zero status, thus causing the job to be terminated. The first process to do so was: Process name: [[56840,1],1] Exit code: 1
复现信息
自定义结构体类定义:
class structtype: def __init__(self): pass
复现主逻辑:
from mpi4py import MPI import os data = [4,5] num_SMOs = 5 solns_list = [] comm = MPI.COMM_WORLD size = comm.Get_size() rank = comm.Get_rank() name = MPI.Get_processor_name() pid = os.getpid() idx = range(num_SMOs) myidx = idx[rank:len(idx):size] for node in myidx: soln_node = structtype() # 给结构体赋值 soln_node.node_num = node soln_node.XX = data solns_list.append(soln_node) # 所有进程将本地solns_list发送到0号进程 solns_nodes_all = comm.gather(solns_list, root=0) if rank == 0: for soln_node in solns_nodes_all: node_num = soln_node.node_num data = soln_node.XX
错误原因
comm.gather的返回值仅在指定根进程上有效,返回结构为长度等于总进程数的列表,列表第i位的元素就是rank为i的进程传入的发送对象。
每个进程传入gather的发送对象是solns_list,本身是存储多个结构体实例的列表,因此根进程拿到的solns_nodes_all是两层嵌套列表:第一层按rank顺序存储每个进程发来的子列表,第二层子列表内才是单个结构体对象。原代码直接遍历第一层列表,取出的元素是子列表而非结构体实例,自然无法直接访问结构体属性。
修复方案
根进程处理gather返回值时,先遍历每个进程发来的子列表,再遍历子列表内的结构体对象即可,两种实现方式都可以:
- 两层循环直接处理,无需额外存储
if rank == 0: for proc_soln_list in solns_nodes_all: for soln_node in proc_soln_list: node_num = soln_node.node_num data = soln_node.XX # 写入后续业务处理逻辑
- 先展开嵌套列表得到一维的全量结构体列表,再做后续处理,如果需要按node_num排序可以在展开后追加排序逻辑
if rank == 0: all_soln_nodes = [] for proc_soln_list in solns_nodes_all: all_soln_nodes.extend(proc_soln_list) # 如需按节点号排序,放开下一行注释 # all_soln_nodes.sort(key=lambda x:x.node_num) for soln_node in all_soln_nodes: node_num = soln_node.node_num data = soln_node.XX # 写入后续业务处理逻辑
内容的提问来源于stack exchange,提问作者jvineet9
相关产品推荐
相关产品推荐

