47494


ミュージックプレイヤーを個人で作っています。  
言語：Python 3.7  
環境：VS2017 community  
OS：windows 10 64bit  
cpu：core i3

プログラミング初心者です。頓珍漢なことを書いていたら指摘してください。  
音楽CD（wav,16bit,44100Hz）からwavファイルを読み込んでギャップレス再生できるように  
するために、numpyの配列で全曲を連結することをしております。  
「読み込み＆連結」の時間を短縮するために、CDアルバム内の14曲のファイルを  
２つのリストに振り分けてから「wavファイルデータの読み込み＆連結」を  
２プロセスで平行処理したいと思っています。

詳細：  
リスト内データサイズは300MBあたりを境界として２つのリスト「self.fl1ba,self.fl1bb」に  
分割しております。  
そのあと、「self.fl1ba」と「self.fl1bb」からmultiprocessingのProcessクラスを  
使用して平行処理で時間短縮をしようとしています。  
しかし、Processを設定して「start()」しても平行処理になってくれません。  
vstack1 = mp.Process(target=stack.fl_vstack1())  
「.fl_vstack1()」の「()」を削除すると動かなくなります。  
Poolクラスでも試しましたが、調べてみると、Poolの場合、「map」を使うでnumpy.arrayの  
２次元配列は処理できないようでした。

wavファイル読み込みモジュールはpysoundfileを使用しています。  
data,fs=soundfile.read(ファイル,dtype='int16')で２次元データ配列(data)と  
サンプリング周波数(fs)が得られます。  
再生はsounddeviceモジュールを使用。コードをここに入力

ファイル読み込み＆連結を平行処理する方法をご教示ください。  
よろしくお願いします。

補足1：  
nekketsuuuさん、回答ありがとうございます。  
回答いただいたソースではうまく5(s)程度で処理してくれまた。  
しかし、私のコードでは関数が「def
fl_vstack1(self)」となっているためか、「args=()」とすることで「self」が「None」に置き換わってしまった気がします。実行すると、関数の  
「def
fl_vstack1(self)」は実行されませんでした。関数内の処理そのものが動いていないと思います。というのも、array配列「self.sumdata1」を初期化したとき代入した[0,0]を関数内で削除しているのですが、それも実行されていなかったためです。Processクラスでは「self」を使えないのでしょうか？ご教示よろしくお願いします。

補足2：  
metropolisさん、コメントありがとうございます。  
ご指摘どおりログをとってみました。なんと！「vstack1」と「vstack2」のプロセスは動作しておりました。別の問題で最後まで実行されていないことが分かりました。  
別の問題とは、２プロセスの「vstack1」と「vstack2」で処理した値が次の２プロセスの「tvstack1」と「tvstack2」へ受け渡されていないことです。「self」に格納されるものと思っていたのですが、違うことが分かりました。「Pipe」や「Queue」というものを使えばいいのか、これから調べます。

[code]

    import os
    import multiprocessing as mp
    import numpy as np
    import time
    import soundfile as sf
    import sounddevice as sd
    
    class Fileread():
    
        def __init__(self):
                    
        ### ディレクトリから「wavファイル」のみをself.fl1bに取得 ###
            os.chdir("C:/Users/Public/Music/Music Center/Shared/Music/Aerosmith/Unplugged 1990 (Live)")
            dir1 = os.getcwd()
            self.dir2 = os.listdir(dir1)
            
            self.fl1b = []
            for j in self.dir2:
    
                base,ext = os.path.splitext(j)
    
                if ext == '.wav':
    
                    self.fl1b.append(j)
            
            self.sumflsize1 = 0
            self.sumflsize2 = 0
            
            self.fl1c1 = []
            self.fl1c2 = []
    
            self.fl1ba = []        
            self.fl1bb = []
    
            self.sumdata1 = np.array([0,0],dtype='int16')
            self.sumdata2 = np.array([0,0],dtype='int16')
    
            self.fl1t1 = []
            
            self.fs = 0
    
    
    
    
            ### リスト内ファイルを２分割するメソッドを格納 ###
            self.split_album()
    
        ### リストとして取得したファイルを別の２つのリストに２分割 ###
        def split_album(self):
    
            flsize = []
            
            ### アルバム内の各ファイルサイズを取得 ###
            for h in self.fl1b:
    
                flsize.append(os.path.getsize(h))
    
    
            ### アルバム内ファイルをリスト「self.fl1ba」と「self.fl1bb」に格納 ###
            list_len = len(self.fl1b)
            
            for d in range(list_len):
    
                self.sumflsize1 += flsize[d]
                self.fl1ba.append(self.fl1b[d])
                    
                if self.sumflsize1 > 300000000:
    
                    break
    
            for q in range(list_len):
    
                if q <= d:
                    pass
                else:
                    self.sumflsize2 += flsize[q]
                    self.fl1bb.append(self.fl1b[q])
    
        ### リスト「self.fl1ba」内の各ファイルを'int16'で取得し、「self.sumdata1」に追加 ###
        def fl_vstack1(self):
            
            list_len1 = len(self.fl1ba)
    
            for k in range(list_len1):
    
                data,fs = sf.read(self.fl1ba[k],dtype='int16')
                self.fs = fs  ### fsはサンプリング周波数 ###
                
                frame_num = len(data)
                self.fl1c1.append(frame_num) ### 各ファイルの再生時間を算出するためにフレーム数を取得 ###
                self.sumdata1 = np.vstack((self.sumdata1,data)) ### 「self.sumdata1」にwavファイルから読み込んだdataを追加 ###
    
    
            self.sumdata1 = np.delete(self.sumdata1,0,0)
    
        ### 「fl_vstack1」と同じことを「self.fl1bb」内のファイルについても実行 ###
        def fl_vstack2(self):
    
            list_len2 = len(self.fl1bb)
    
            if list_len2 > 0:  ### リスト「self.fl1bb」にファイルが存在する場合 ###
    
                for k in range(list_len2):
    
                    data,fs = sf.read(self.fl1bb[k],dtype='int16')
    
                    frame_num = len(data)
                    self.fl1c2.append(frame_num)
                    self.sumdata2 = np.vstack((self.sumdata2,data))
    
                self.sumdata2 = np.delete(self.sumdata2,0,0)            
    
            else:
                pass
    
        ### 「fl_vstack1」と「fl_vstack2」で積み上げたデータを連結 ###
        def sum_stack(self):
    
            self.sumdata1 = np.vstack((self.sumdata1,self.sumdata2))
            
        ### 各ファイル（曲）の演奏時間を算出 ###
        def sum_time(self):
    
            self.fl1c1 = self.fl1c1 + self.fl1c2
            self.fl1t1 = list(map(lambda x: x/self.fs/60,self.fl1c1))
    
        ### 連結したファイルを再生（ギャップレス再生） ###
        def sdplay(self):
    
            sd.play(self.sumdata1,self.fs)
            status = sd.wait()
    
    
    if __name__=='__main__':
    
        stack = Fileread()
    
        ### プロセス「vstack1」と「vstack2」が平行して動かない ###
        ### vstack1.start()ではなく下記プロセス設定時に処理が始まっているようです ###
        ### 「stack.fl_vstack1()」の「()」を削除して実行すると処理してくれません ###
        start1 = time.time()
        vstack1 = mp.Process(target=stack.fl_vstack1())
        print('stack1:',time.time() - start1)
        vstack2 = mp.Process(target=stack.fl_vstack2())
        print('stack2:',time.time() - start1)
        
    
        vstack1.start()
        vstack2.start()
        
        vstack1.join()
        vstack2.join()
    
        tvstack1 = mp.Process(target=stack.sum_stack())
        tvstack2 = mp.Process(target=stack.sum_time())
        tvstack1.start()
        tvstack2.start()
        tvstack1.join()
        tvstack2.join()
    
    
        tvstack3 = mp.Process(target=stack.sdplay())
        tvstack3.start()
    
[/code]


CC BY-SA 4.0
2018-08-13T13:36:44.390
47492
2023-11-13T08:13:56.890
2023-11-13T08:13:56.890
3060
29720
question
python python3 python-multiprocessing
python3 multiprocessing Processでプロセスが平行で動いてくれません


質問者さんがおっしゃる通り、現在のコードでは以下の行で `fl_vstack1` 関数が呼び出されてしまっています。

[code]

    vstack1 = mp.Process(target=stack.fl_vstack1())
    
[/code]

この行では引数 `target` に `stack.fl_vstack1()` を代入していますが、これは関数呼び出しの構文なので関数呼び出しが起こり、その
**返り値** が `target` に代入されています。本当に代入したかったのは `fl_vstack1` という **関数そのもの**
であったはずです。

こうする代わりに、下のように `args` を長さ 0 のタプルとして指定してください。つまり、`target` に関数自体を、`args`
に引数を指定している形です。この使い方は [`multiprocessing.Process`
のドキュメント](https://docs.python.org/ja/3/library/multiprocessing.html#the-
process-class)に書かれています。

[code]

    vstack1 = mp.Process(target=stack.fl_vstack1, args=())
    
[/code]

こうすると上手くいくことは質問文中の長いソースコードだと分かりにくいかもしれません。この部分の動作だけ確認できるサンプルコードを用意しましたので、必要に応じてご利用ください。

[code]

    import multiprocessing as mp
    import time
    
    def f():
        time.sleep(5)
    
    if __name__ == '__main__':
        process1 = mp.Process(target=f, args=())
        process2 = mp.Process(target=f, args=())
    
        # 並列に実行されているなら、"Start!" から "Finish!" まで大体 5 秒のはずです。
        print("Start!")
        process1.start()
        process2.start()
    
        process1.join()
        process2.join()
        print("Finish!")
    
[/code]


CC BY-SA 4.0
2018-08-13T14:51:48.937
47494
2018-08-13T23:37:28.303
2018-08-13T23:37:28.303
19110
19110
47492
answer