st_time = time.perf_counter()
comm.send(pb, dest=1, tag=1)
prob = comm.recv(source=1, tag=2)
gen_time = time.perf_counter() - st_time
今までは逐次処理になっていたので、これで時間計測ができた。
しかし、本当の並列処理では、次々にパターンをワーカーに送り、送った順番とは関係なく、出来た順番で問題を受取り、次のパターンを送る。そうなると、マスター側で問題生成時間を計測するのは無理で、ワーカー側で計測しないといけない。
ワーカー側で時間計測するのは簡単だ。
まず、現状のworker()を確認してみよう。
def worker():
status = MPI.Status()
while( True ):
prob = comm.recv(source=0, tag=MPI.ANY_TAG, status=status)
if status.Get_tag()!=1:
break
prob.retrycount = generator.generate(prob.pattern)
prob.problem = generator.getProblem()
comm.send(prob, dest=0, tag=2)
実行時間は、 generator.generate(prob.pattern) の実行に掛かった時間で良いので、この1行の直前、直後で現在時刻を計測し、その差を求めれば良い。
そして、実行時間をマスターに伝えなければいけないので、Problemクラスにtimeを追加し、そこ(prob.time)に計算結果を突っ込んでおくと、Problemオブジェクトであるprobがマスターに送られるときにマスターに渡る。
ということで、worker()は以下のようになった。
def worker():
status = MPI.Status()
while( True ):
prob = comm.recv(source=0, tag=MPI.ANY_TAG, status=status)
if status.Get_tag()!=1:
break
st_time = time.perf_counter()
prob.retrycount = generator.generate(prob.pattern)
prob.time = time.perf_counter() - st_time
prob.problem = generator.getProblem()
comm.send( prob, dest=0, tag=2 )
マスター側では時間計測しないので、その部分を削除する。そして、受け取ったProblemオブジェクトprobの中にある時間(prob.time)を時間表示に使う。
for pb in problems:
# パターンの送信、問題の受信
comm.send(pb, dest=1, tag=1)
prob = comm.recv(source=1, tag=2)
genproblems.append(prob)
str = f"No.{prob.index} H {util.countHint(prob.pattern)}"
print(str)
if dataoutput != None:
print(str,file=dataoutput)
util.printHintBoard(prob.pattern)
if prob.retrycount >= 0:
if dataoutput != None:
util.printBoard(prob.problem,dataoutput)
print( f"[{prob.retrycount}] {prob.time:06f} sec" )
util.printBoard(prob.problem)
successCount += 1
else:
str = f"FAILURE {-prob.retrycount}"
if dataoutput != None:
print(str,file=dataoutput)
print(str)
failureCount += 1
print()
comm.send("END", dest=1, tag=9)
print( f"length of genproblems = {len(genproblems)}" )
exe_time = time.perf_counter() - start_time
probSize = len(problems)
totalCount = successCount+failureCount
print( f"total {totalCount} failure {failureCount}\n" )
print( f"Time\t{exe_time:06f} sec\n" )
現状では、2台しか動かしていないので、右の2台のRaspberry PiのLANポートのLEDだけが光っている状況である。2台の間での通信しかないので、LEDのチカチカはほぼ同期する。
NP_MPIGEN2.pyは、まだ並列処理にはなっていないのだが、動作確認しておこう。
$ mpiexec -H RP0,RP1 python3 NP_MPIGEN2.py -g data/Pattern500.txt
No.0 H 18
- - - - X - - - -
- - - X - X - - -
X X - - - - X - -
- - X - - X - - -
- X - - - - - X -
- - - X - - X - -
- - X - - - - X X
- - - X - X - - -
- - - - X - - - -
[0] 0.646241 sec
- - - - 1 - - - -
- - - 4 - 9 - - -
8 6 - - - - 7 - -
- - 9 - - 4 - - -
- 3 - - - - - 7 -
- - - 8 - - 6 - -
- - 4 - - - - 1 9
- - - 7 - 6 - - -
- - - - 2 - - - -
中略
No.499 H 23
- - X X - - - - -
- - X - - X - - -
- - - - - X - X X
- X X X - X - - X
- - - - - - - - -
X - - X - X X X -
X X - X - - - - -
- - - X - - - - -
- - - - - X X - -
[0] 0.056796 sec
- - 7 3 - - - - -
- - 1 - - 9 - - -
- - - - - 8 - 6 4
- 7 9 1 - 2 - - 8
- - - - - - - - -
8 - - 7 - 4 3 1 -
3 5 - 4 - - - - -
- - - 5 - - - - -
- - - - - 7 6 - -
length of genproblems = 500
total 500 failure 0
Time 1124.461174 sec
$
前回、NP_MPIGEN1.pyを実行では 1732秒だったが、今回はNP_MPIGEN2.pyを実行して1124秒だった。しかし、これはプログラムが改善して速くなったのではなく、乱数を使っているため、たまたま問題が速く作れたに過ぎない。
さて、次回は本当の並列処理、複数台のラズパイに問題生成を割り振ることに手を付けよう。