ピット 1: apply_async によって呼び出されたサブ関数が実行されないか、不完全に実行される
解決策: apply_async の使用時にエラーをチェックするために error_callback を渡します。
from multiprocessing import Pool
def processFolder(idx, folders, o_dir):
train_mesh = TrainMeshes(folders)
output_path = os.path.join(o_dir, str(idx) + '.pkl')
pickle.dump(train_mesh, file=open(output_path, "wb"))
if __name__ == '__main__':
train_mesh_folders = ['mesh1','mesh2']
n_processes = os.cpu_count()
n_processes =2
print('n_processes: ', n_processes)
pool = Pool(processes=n_processes) # 进程池
# split folders into n_processes parts
split_folders = np.array_split(train_mesh_folders, n_processes)
pool.apply_async(processFolder, args=(0, split_folders[0], output_dir,))
pool.apply_async(processFolder, args=(1, split_folders[1], output_dir,))
pool.close()
pool.join()
上記のマルチプロセス プログラムを実行すると、呼び出されたプログラムはほんの一部が実行されただけで終了し、エラーは報告されません。
ややこしい。
エラーが無いように見えますが、実はエラーがあります!!!上記のプログラム pool.apply_async にerror_callback を
追加すると、問題が見つかります。
from multiprocessing import Pool
def processFolder(idx, folders, o_dir):
train_mesh = TrainMeshes(folders)
output_path = os.path.join(o_dir, str(idx) + '.pkl')
pickle.dump(train_mesh, file=open(output_path, "wb"))
def error_callback(e):
print('error_callback: ', e)
if __name__ == '__main__':
train_mesh_folders = ['mesh1','mesh2']
n_processes = os.cpu_count()
n_processes =2
print('n_processes: ', n_processes)
pool = Pool(processes=n_processes) # 进程池
# split folders into n_processes parts
split_folders = np.array_split(train_mesh_folders, n_processes)
pool.apply_async(processFolder, args=(0, split_folders[0], output_dir,), error_callback=error_callback)
pool.apply_async(processFolder, args=(1, split_folders[1], output_dir,), error_callback=error_callback)
pool.close()
pool.join()
ご覧のとおり、エラーがあります。!!!
しかし、これは非常に奇妙なことでもあります。マルチプロセスを使用しない場合、エラーは報告されません。もしかしたら私のプログラムがうまく書かれていないのかもしれません。いずれにせよ、エラーが報告された後は、マルチプロセスはスムーズに実行できるようになります。
参考文献:
Python プロセス プールの apply_async のコールバック関数が実行されない場合の解決策
Python 同時プログラミング: プロセス プールに渡されたターゲット関数が実行されず、エラーが報告されないのはなぜですか?
ピット 2: マルチプロセス インポート プールからのプロセス プールのトーチ関連機能のスタック
torch.min(V[:,0])
torch.sparse.FloatTensor(i, v, torch.Size(shape))
両方の関数がスタックすることが測定されます
解決策: プロセスの代わりにスレッドを使用し、multiprocessing.pool から変更して ThreadPool をプールとしてインポートします
def normalizeUnitCube(V):
'''
NORMALIZEUNITCUBE normalize a shape to the bounding box by 0.5,0.5,0.5
Inputs:
V (|V|,3) torch array of vertex positions
Outputs:
V |V|-by-3 torch array of normalized vertex positions
'''
V = V - torch.min(V,0)[0].unsqueeze(0)
# x_min = torch.min(V[:,0])
# y_min = torch.min(V[:,1])
# z_min = torch.min(V[:,2])
# min_bound = torch.tensor([x_min, y_min, z_min]).unsqueeze(0)
# V = V - min_bound
V = V / torch.max(V.view(-1)) / 2.0
return V
上記の関数は点のセットを正規化します。V は 2 次元テンソルで、実際には (Nx3) 個の頂点のリストです。
torch.min(V,0) を使用した実際の測定はスタックし、コメントされたコードしか使用できません。torch.min(V[:,0]) を実行します。
def tgp_midPointUp(V, F, subdIter=1):
"""
perform mid point upsampling
"""
Vnp = V.data.numpy()
Fnp = F.data.numpy()
VVnp, FFnp, SSnp = midPointUpsampling(Vnp, Fnp, subdIter)
VV = torch.from_numpy(VVnp).float()
FF = torch.from_numpy(FFnp).long()
SSnp = SSnp.tocoo()
values = SSnp.data
indices = np.vstack((SSnp.row, SSnp.col))
i = torch.LongTensor(indices)
v = torch.FloatTensor(values)
shape = SSnp.shape
SS = torch.sparse.FloatTensor(i, v, torch.Size(shape)) #在这里会卡死
return VV, FF, SS
一般的なソリューション
- pathos パッケージの下の multiprocessing モジュールを呼び出して、元の multiprocessing を置き換えます。pathos のマルチプロセッシングは、ほぼすべての Python 型をシリアル化できる dill パッケージで書き直されているため、すべてをピクル化できます。
- multiprocessing.pool からのプロセスの代わりにスレッドを使用して、ThreadPool をプールとしてインポートします
- copy_reg を使用して例外を回避できます
- これを避けるために、呼び出される関数をトップレベルに記述します。
- クラスの内部関数をオーバーライドして回避します。