前提・実現したいこと
現在、Pythonで画像のグレースケールに変換する処理を並列で実行しようとしています。
そこでconcurrent.futuresのProcessPoolExecutorでmax_workerに5コア以上入れた場合2〜4コアと比べてあまり高速化されてないでのですが、原因がわからず困っております。
他のサイトを見てみても5コア以上はそこまで高速化できてないようですが、それがなぜかまでは説明されておりませんでした、、、
なので、原因ともしうまく高速化出来るのであれば教えて頂きたいです。
また、同じ要領でThredPoolExecutorを利用した場合スレッドの本数を2〜40にしてもシングルスレッドの実行結果と変わらなかったのですがなぜマルチスレッドでは全く高速化出来なかったのかも合わせて質問さて頂きたいです。
今回初めて、マルチプロセスやマルチスレッドを触るので理解が甘いのと処理がおかしいところもあるかもしれないです。。。
該当のソースコード
Python3
1""" 2並列で画像をモノクロにする 3画像をコマンドライン引数で渡しておく 4例)python ParallelMono.py 画像.pngとか 5事前に 6 pip install opencv-python 7 pip install matplotlib 8 pip install futures 9をしておく""" 10 11# スレッドで並列化を利用する為に必要なモジュール 12import concurrent.futures 13 14# その他各ライブラリをインポート 15import matplotlib.pyplot as plt 16import numpy as np 17import cv2 18import common 19import sys 20import os 21import time 22 23# コンソールをクリア 24os.system('clear') 25 26# コマンドライン引数から画像を読み込む 27img = common.getRGBImage( sys.argv[1] ) 28 29# 使用数を初期化 30useThread = 1 31useCPU = 1 32 33def main(): 34 # スレッドかCPUか選ぶ 35 msg = "マルチスレッドかマルチプロセスどちらにしますか?\n"\ 36 "[1:マルチスレッド 2:マルチプロセス] : " 37 multchType = int( input(msg.format(os.cpu_count())) ) 38 # 使用する数を選択 39 if multchType == 1: 40 useThread = int( input("使用するスレッドの数を入力してください : ") ) 41 if useThread > 1: 42 mulchThread(useThread= useThread) 43 plt.imshow(img) 44 plt.show() 45 else: 46 print("0以下なので終了") 47 elif multchType == 2: 48 useCPU = int( input("使用するCPUのコアを入力してください[ 1 ~ {0} ] : ".format(os.cpu_count())) ) 49 if useCPU >= 1 and useCPU <= os.cpu_count(): 50 mulchProcess(useCPU= useCPU) 51 plt.imshow(img) 52 plt.show() 53 else: 54 print("選択の範囲外なので終了") 55 else: 56 print("どちらでもないので終了") 57 58def changeToGray( number: int, width: np.ndarray ): 59 """ 60 並列化する処理 61 @param number (int) : このプロセスの番号 62 @param width (np.ndarray) : 横1行の配列[ [R, G, B], ・・・・ ,[R, G, B] ] 63 @return number (int) : このプロセスの番号 64 @return width (np.ndarray) : 引数で受け取った配列をグレースケールに変換した配列 65 """ 66 for pixel in width: 67 # グレースケールにするする処理 68 gray = int(pixel[0]*0.3) + int(pixel[1]*0.59) + int(pixel[2]*0.11) 69 pixel[0] = gray # Red 70 pixel[1] = gray # Green 71 pixel[2] = gray # Blue 72 return number, width 73 74def mulchProcess(useCPU: int): 75 """ 76 マルチコアでプロセスを生成して実行させる処理 77 @param useCPU (int) : 使用するCPUのコア数 78 """ 79 print("") 80 start = time.time() 81 count = 0 82 print("{0}コアで処理を開始します!!".format(useCPU)) 83 with concurrent.futures.ProcessPoolExecutor(max_workers=useCPU) as executer: 84 fs = [ executer.submit(changeToGray, i, width) for width, i in zip( img, range(len(img)) ) ] 85 for future in concurrent.futures.as_completed(fs): 86 line_number = future.result()[0] 87 gray_width = future.result()[1] 88 img[line_number] = gray_width 89 count += 1 90 common.progressBar(count, len(img)) 91 print("\n終了しました!!") 92 print("かかった時間:{0}秒".format( time.time()-start )) 93 94def mulchThread(useThread: int): 95 """ 96 スレッドを生成して実行させる処理 97 @param useThread (int) : 使用するスレッドの数 98 """ 99 print("") 100 start = time.time() 101 count = 0 102 print("{0}スレッドで処理を開始します!!".format(useThread)) 103 with concurrent.futures.ThreadPoolExecutor(max_workers=useThread) as executer: 104 fs = [ executer.submit(changeToGray, i, width) for width, i in zip( img, range(len(img)) ) ] 105 for future in concurrent.futures.as_completed(fs): 106 line_number = future.result()[0] 107 gray_width = future.result()[1] 108 img[line_number] = gray_width 109 count += 1 110 common.progressBar(count, len(img)) 111 print("\n終了しました!!") 112 print("かかった時間:{0}秒".format( time.time()-start )) 113 114if __name__ == '__main__': 115 main()
試したこと
色々、コアの数を変更したりスレッドを利用したりしてみましたがなかなか成果か現れません。
補足情報(FW/ツールのバージョンなど)
[実行環境]
MacBook Pro (15-inch, 2016)
プロセッサ : 2.6 GHz Intel Core i7 ( 4コア8スレッド )
メモリ : 16 GB 2133 MHz LPDDR3
Python 3.6.4
[実行結果]
1コア:93.36475276947021秒 100%
2コア:45.95268726348877秒 約203%
3コア:32.04803204536438秒 約291%
4コア:25.691081047058105秒 約363%
5コア:25.711262941360474秒 約363%
6コア:24.469857692718506秒 約381%
7コア:23.86842966079712秒 約391%
8コア:23.69063401222229秒 約394%
回答2件