0

マルチプロセッシング(MP)と、非MPバージョンとの比較で可能な速度向上を理解するために、以下のコードを書きました。2 つの機能は、強調表示された場所を除いてほとんど同じです (申し訳ありませんが、コード領域を強調表示するより良い方法を知りませんでした)。

このコードは、配列のリスト (ここでは 1-D) 内の冗長エントリのインデックスを識別しようとします。2 つの関数によって返される ID リストは同じですが、私の質問は時間差に関するものです。

ご覧のとおり、a) map 関数、b) リスト拡張、および c) while ループ全体の両方のケースで時間を計ろうとしました。mapMP はリージョンにいる間は速度が向上しますが、redun_ids.extend(...)非 MP バージョンに比べて遅くなります。これは実際、MP バージョンによる全体的な速度の向上を強制的に低下させています。

redun_ids.extend(...)非 MP バージョンと同じタイミングになる ように、MP バージョンの部分を書き直す方法はありますか?

#!/usr/bin/python
import multiprocessing as mproc
import sys
import numpy as np
import random
import time

def matdist(mats):
        mat1 = mats[0]
        mat2 = mats[1]
        return np.allclose(mat1, mat2, rtol=1e-08, atol=1e-12)

def mp_remove_redundancy(larrays):
        """
        remove_redundancy : identify arrays that are redundant in the
        input list of arrays
        """
        llen = len(larrays)
        redun_ids = list()
        templist = list()
        i = 0
        **pool = mproc.Pool(processes=10)**
        st1=time.time()
        while 1:
                currarray = larrays[i]
                if i not in redun_ids:
                        templist.append(currarray)
                        #replication to create list of arrays
                        templist = templist*(llen-i-1)
                        **chunksize = len(templist)/10
                        if chunksize == 0:
                                chunksize = 1**
                        #clslist is a result object here
                        st=time.time()
                        **clslist = pool.map_async(matdist, zip(larrays[i+1:],
                                templist), chunksize)**
                        print 'map time:', time.time()-st
                        **outlist = clslist.get()[:]**
                        #j+1+i gives the actual id num w.r.t to whole list
                        st=time.time()
                        redun_ids.extend([j+1+i for j, x in
                                enumerate(outlist) if x])
                        print 'Redun ids extend time:', time.time()-st
                i = i + 1
                del templist[:]
                del outlist[:]
                if i == (llen - 1):
                        break
        print 'Time elapsed in MP:', time.time()-st1
        pool.close()
        pool.join()
        del clslist
        del templist
        return redun_ids[:]
#######################################################
def remove_redundancy(larrays):
        llen = len(larrays)
        redun_ids = list()
        clslist = list()
        templist = list()
        i = 0
        st1=time.time()
        while 1:
                currarray = larrays[i]
                if i not in redun_ids:
                        templist.append(currarray)
                        templist = templist*(llen-i-1)
                        st = time.time()
                        clslist = map(matdist, zip(larrays[i+1:],
                                templist))
                        print 'map time:', time.time()-st
                        #j+1+i gives the actual id num w.r.t to whole list
                        st=time.time()
                        redun_ids.extend([j+1+i for j, x in
                                enumerate(clslist) if x])
                        print 'Redun ids extend time:', time.time()-st
                i = i + 1
                #clear temp vars
                del clslist[:]
                del templist[:]
                if i == (llen - 1):
                        break
        print 'Tot non MP time:', time.time()-st1
        del clslist
        del templist
        return redun_ids[:]
###################################################################

if __name__=='__main__':
        if len(sys.argv) != 2:
                sys.exit('# entries')
        llen = int(sys.argv[1])
        #generate random numbers between 1 and 10
        mylist=[np.array([round(random.random()*9+1)]) for i in range(llen)]
        print 'The input list'
        print 'no MP'
        rrlist = remove_redundancy(mylist)
        print 'MP'
        rrmplist = mp_remove_redundancy(mylist)
        print 'Two lists match : {0}'.format(rrlist==rrmplist)
4

2 に答える 2

1

MPシナリオの「ファンイン」領域でパフォーマンスが低下するのはごく普通のことだと思います。これは、multiprocessing共有メモリでは発生しないと思われる通信コストが発生するためです。

「ファンアウト」フェーズ (つまり への呼び出しmap_async) では、親プロセスは numpy 配列をシリアル化し、それらを子プロセスに送信する必要があります (Unix ドメイン パイプ経由だと思います)。 .

逆に、「ファンイン」フェーズでは、子がシリアル化して送信し、親が受信して逆シリアル化してから、呼び出しextendてそれらをまとめることができます。

私が完全に確信していないのはextend、ボトルネックがへの呼び出しにあると本当に予想しているときに、それ自体への呼び出しに費やされた時間が長いことを検出している理由ですget()。しかし、ここでも、これ以上深く掘り下げるには十分な情報がありません。例:get()デシリアライズされた numpy 配列、またはへの呼び出し中に遅延計算される単なるプロキシを返しextendますか?

そして、繰り返しますが、私たちはどのタイミングについて話しているのですか? time.time()数ミリ秒について話している場合、Pythonは C/C++ の世界から来ている場合に期待するほど正確ではないことに注意してください。その時間範囲内で、Python の世界では、インタープリター側で非常に多くのことが起こっているため、そのような小さな数字から明確な意味を理解することは非常に困難です。

于 2012-08-17T08:57:32.470 に答える
0

clslist = pool.map_async(...)リクエストを送信するだけなので非常に高速です。マップ操作全体の時間clslist.get()を計測する場合は、結果を待機する を含めます。

于 2012-08-17T08:43:49.720 に答える