処理する必要のある膨大なリストがあり、時間がかかるので、4つに分割して、それぞれの部分を何らかの機能でマルチプロセスします。4コアで実行するにはまだ少し時間がかかるので、リストの処理で各プロセッサがどこにあるかを教えてくれるように、関数にプログレスバーを追加することにしました。
私の夢はこのようなものを持つことでした:
erasing close atoms, cpu0 [######..............................] 13%
erasing close atoms, cpu1 [#######.............................] 15%
erasing close atoms, cpu2 [######..............................] 13%
erasing close atoms, cpu3 [######..............................] 14%
関数のループが進むにつれて、各バーが移動します。しかし、代わりに、私は継続的な流れを得る:
など、ターミナルウィンドウを埋めます。
関数を呼び出すメインのPythonスクリプトは次のとおりです。
from eraseCloseAtoms import *
from readPDB import *
import multiprocessing as mp
from vectorCalc import *
prot, cell = readPDB('file')
atoms = vectorCalc(cell)
output = mp.Queue()
# setup mp to erase grid atoms that are too close to the protein (dmin = 2.5A)
cpuNum = 4
tasks = len(atoms)
rangeSet = [tasks / cpuNum for i in range(cpuNum)]
for i in range(tasks % cpuNum):
rangeSet[i] += 1
rangeSet = np.array(rangeSet)
processes = []
for c in range(cpuNum):
na, nb = (int(np.sum(rangeSet[:c] + 1)), int(np.sum(rangeSet[:c + 1])))
processes.append(mp.Process(target=eraseCloseAtoms, args=(prot, atoms[na:nb], cell, 2.7, 2.5, output)))
for p in processes:
p.start()
results = [output.get() for p in processes]
for p in processes:
p.join()
atomsNew = results[0] + results[1] + results[2] + results[3]
以下は関数eraseCloseAtoms()
です:
import numpy as np
import click
def eraseCloseAtoms(protein, atoms, cell, spacing=2, dmin=1.4, output=None):
print 'just need to erase close atoms'
if dmin > spacing:
print 'the spacing needs to be larger than dmin'
return
grid = [int(cell[0] / spacing), int(cell[1] / spacing), int(cell[2] / spacing)]
selected = list(atoms)
with click.progressbar(length=len(atoms), label='erasing close atoms') as bar:
for i, atom in enumerate(atoms):
bar.update(i)
erased = False
coord = np.array(atom[6])
for ix in [-1, 0, 1]:
if erased:
break
for iy in [-1, 0, 1]:
if erased:
break
for iz in [-1, 0, 1]:
if erased:
break
for j in protein:
protCoord = np.array(protein[int(j)][6])
trueDist = getMinDist(protCoord, coord, cell, vectors)
if trueDist <= dmin:
selected.remove(atom)
erased = True
break
if output is None:
return selected
else:
output.put(selected)
コードに2つの問題があります。
The first one explains why your progress bars are often showing 100%
rather than their real progress. You're calling bar.update(i)
which advances the bar's progress by i
steps, when I think you want to be updating by one step. A better approach would be to pass the iterable to the progressbar
function and let it do the updating automatically:
with click.progressbar(atoms, label='erasing close atoms') as bar:
for atom in bar:
erased = False
coord = np.array(atom[6])
# ...
However, this still won't work with multiple processes iterating at once, each with its own progress bar due to the second issue with your code. The click.progressbar
documentation states the following limitation:
No printing must happen or the progress bar will be unintentionally destroyed.
This means that whenever one of your progress bars updates itself, it will break all of the other active progress bars.
これを簡単に修正できるとは思いません。複数行のコンソール出力をインタラクティブに更新することは非常に困難です(基本的に、OSのサポートを受けてcursesまたは同様の「コンソールGUI」ライブラリを使用する必要があります)。click
モジュールは、それだけで現在の行を更新することができ、その機能を持っていません。次のように、click.progressbar
デザインを拡張して複数のバーを列に出力することをお勧めします。
CPU1: [###### ] 52% CPU2: [### ] 30% CPU3: [######## ] 84%
これを機能させるには、重要な量のコードが必要になりますが(特に、更新が複数のプロセスから行われる場合)、完全に実用的ではありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加