質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
並列処理

複数の計算が同時に実行される手法

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1815閲覧

Pythonのmultiprocessingで、wavからmp3への変換を行いたい

moootoko_ojisan

総合スコア32

並列処理

複数の計算が同時に実行される手法

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/07/24 16:55

前提・実現したいこと

自宅にあるNASからスマホで音楽を聞くために、wavファイルをmp3ファイルに変換するPythonスクリプトを作っています。
はじめは逐次的に変換するコードを書いていましたが、非常に時間がかかるので並列処理に変えようとしています。

発生している問題・エラーメッセージ

最後まで変換されずに途中で終わってしまいます。
どの曲を変換しているかログを出すようにして実行したところ、マルチな子プロセスが変換処理を始めたログがでて数十秒後に何事もなくメインプロセスが終了します。
変換終了ログも出ていません。
期待値は「すべてのwavファイルがmp3ファイルに変換されること」です。

該当のソースコード

python

1# transform_multiprocess.py 2import os 3import glob 4import pydub 5import multiprocessing 6from datetime import datetime 7 8 9# ファイル名をキューに登録する 10def produce(queue, wavpath_list): 11 for i in range(len(wavpath_list)): 12 wavpath = wavpath_list[i] 13 writelog(f'<Enqueue> {wavpath}') 14 queue.put(wavpath) 15 16 17# キューからファイル名を取り出して変換 18def consume(queue): 19 while not queue.empty(): 20 print(f'queue.isempty = {queue.empty()}') 21 wavpath = queue.get() 22 writelog(f'<Dequeue> {wavpath}') 23 trans_wav_to_mp3(wavpath) 24 25 26# wavからmp3に変換する 27def trans_wav_to_mp3(wavpath): 28 mp3path = wavpath.replace('.wav', '.mp3') 29 writelog(f'Start transforming: {wavpath}') 30 sound = pydub.AudioSegment.from_wav(wavpath) 31 sound.export(mp3path, format='mp3') 32 writelog(f'Finish transforming: {wavpath} -> {mp3path}') 33 del sound 34 35 36# ログファイル書き出し 37def writelog(log): 38 dt_now = datetime.now().strftime('%Y/%m/%d %H:%M:%S') 39 pid = os.getpid() 40 writelog(f'<Enqueue> {wavpath}') 41 queue.put(wavpath) 42 43 44# メイン 45def main(): 46 # wavファイルのリスト 47 wavpath_list = glob.glob( 48 'NAS用HDDのマウントポイント/*.wav', 49 recursive=True 50 ) 51 # ファイル名を格納するキュー 52 queue = multiprocessing.SimpleQueue() 53 54 # プロセス生成 55 p = multiprocessing.Process(target=produce, args=(queue, wavpath_list)) 56 c0 = multiprocessing.Process(target=consume, args=(queue,)) 57 c1 = multiprocessing.Process(target=consume, args=(queue,)) 58 c2 = multiprocessing.Process(target=consume, args=(queue,)) 59 c3 = multiprocessing.Process(target=consume, args=(queue,)) 60 61 # プロセス開始 62 p.start() 63 c0.start() 64 c1.start() 65 c2.start() 66 c3.start() 67 68 # プロセス終了待ち合わせ 69 p.join() 70 c0.join() 71 c1.join() 72 c2.join() 73 c3.join() 74 75 76# main 77if __name__ == '__main__': 78 main()

試したこと

プロセス数をいろいろ変えてみましたが、変わらずでした。

補足情報

Python 3.7.3
OS:Raspbian Buster

(あまり質問を投げたことがないので、情報不足がありましたらすみません...)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2021/07/25 00:42

メモリ不足の可能性はありませんか?
moootoko_ojisan

2021/07/25 12:00

指摘ありがとうございます。 メモリ使用量を表示させて様子を見ようと思います。
guest

回答2

0

以下のソースコードで解決しました。
ありがとうございました。

python

1# trans_wav2mp3_multi.py 2 3import os 4import glob 5import pydub 6import multiprocessing 7from datetime import datetime 8 9 10# wavからmp3へ変換 11def trans_wav_to_mp3(wavpath): 12 mp3path = wavpath.replace('.wav', '.mp3') 13 writelog(f'Start transforming: {wavpath}') 14 sound = pydub.AudioSegment.from_wav(wavpath) 15 sound.export(mp3path, format='mp3') 16 writelog(f'Finish transforming: {wavpath} -> {mp3path}') 17 del sound 18 19 20# 自分用ログ出力 21def writelog(log): 22 dt_now = datetime.now().strftime('%Y/%m/%d %H:%M:%S') 23 pid = os.getpid() 24 text = f'[{dt_now}({pid})] {log}' 25 print(text) 26 with open('log.txt', mode='a') as f: 27 f.write(text+'\n') 28 29 30# メイン 31if __name__ == '__main__': 32 # wav file list 33 wavpath_list = glob.glob( 34 'NAS用HDDマウントポイント/*.wav', 35 recursive=True 36 ) 37 38 # multi processing 39 with multiprocessing.Pool(4) as p: 40 p.map(trans_wav_to_mp3, wavpath_list)

実行中のCPU、メモリの様子は画像のとおりです。
期待通りフルパワーで変換してくれました。
メモリは意外と余裕があったようです。

CPU使用率/メモリ使用率

投稿2021/07/26 16:34

moootoko_ojisan

総合スコア32

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

キューにアイテムを投入するプロセスとキューから取得して処理するプロセスを同時に起動しています。 また、処理するプロセスはキューが空だと停止するようになっています。
キューにデータが入る前にキューが空で終了してしまっているのではないでしょうか?

この問題のように、処理するデータのリストがあらかじめ決っていて、それを並列処理するのであれば、poolを使って処理するのが簡単なのではないかと思います。

未検証ですが、以下のような感じです。

python

1import multiprocessing 2import glob 3 4wavpath_list = glob.glob( 5 'NAS用HDDのマウントポイント/*.wav', 6 recursive=True 7) 8 9with multiprocessing.Pool(processes=4) as pool: 10 pool.map(trans_wav_to_mp3, wavpath_list) 11

投稿2021/07/25 07:56

TakaiY

総合スコア13790

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moootoko_ojisan

2021/07/25 12:04

コメントありがとうございます。 ログの順番と実際の処理の順番は、必ずしも同じとは限らないということですね。 Enqueueのログが最初にバーっと出て、その中にDequeueのログが混ざっている状態でしたが、もしかしたらDequeueが最初に行われたかもしれないと考えました。 Poolの方法で試してみたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問