python3 multiprocessing Processでプロセスが平行で動いてくれません
ミュージックプレイヤーを個人で作っています。
言語:python3.7
環境:VS2017 community
OS:windows 10 64bit
cpu:core i3
プログラミング初心者です。頓珍漢なことを書いていたら指摘してください。
音楽CD(wav,16bit,44100Hz)からwavファイルを読み込んでギャップレス再生できるように
するために、numpyの配列で全曲を連結することをしております。
「読み込み&連結」の時間を短縮するために、CDアルバム内の14曲のファイルを
2つのリストに振り分けてから「wavファイルデータの読み込み&連結」を
2プロセスで平行処理したいと思っています。
詳細:
リスト内データサイズは300MBあたりを境界として2つのリスト「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の
2次元配列は処理できないようでした。
wavファイル読み込みモジュールはpysoundfileを使用しています。
data,fs=soundfile.read(ファイル,dtype='int16')で2次元データ配列(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」のプロセスは動作しておりました。別の問題で最後まで実行されていないことが分かりました。
別の問題とは、2プロセスの「vstack1」と「vstack2」で処理した値が次の2プロセスの「tvstack1」と「tvstack2」へ受け渡されていないことです。「self」に格納されるものと思っていたのですが、違うことが分かりました。「Pipe」や「Queue」というものを使えばいいのか、これから調べます。
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
### リスト内ファイルを2分割するメソッドを格納 ###
self.split_album()
### リストとして取得したファイルを別の2つのリストに2分割 ###
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()