センサーからデータを取り出すための関数が7つあり、これらを直列に実行する場合と並列に処理する場合の実行時間を比較したプログラムを作成しております。各関数の実行時間を1秒としたとき、直列に実行すれば7秒ほどの実行時間がかかりますが、並列処理にすることで2秒ほどに短縮できます。一方で、各関数の実行時間を0.005秒とすると、並列化の恩恵を見込めず、直列処理の実行時間とほぼ同じになりました。
理想的には、並列化をすることで各関数の実行時間ほどに効率化ができればと思ったのですが、目論見は失敗しました。
並列化のために使用しているライブラリはconcurrent.futuresのThreadPoolExecutorを使用しています。
あくまで仮説ですが、PythonにはGILの制約があるため、同時に実行されるスレッドが一つに制約されるので、一つのスレッドを呼び出すための時間 > 各関数の実行時間の関係が成り立つ場合、いくら並列化をしても各関数の実行時間よりも早くなることは無いのではないかと考えています。
(GILロックを回避した並列処理の実装が必要?)
上記に関して改善策や知見などありましたらご教授いただきたいです。
下記は実験に使用したコードになります。よろしくお願いいたします。
python
import time from time import perf_counter import numpy as np from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor def wait_process(wait_sec): until = perf_counter() + wait_sec while perf_counter() < until: pass return def get_euler(waittime): wait_process(waittime) x, y, z = 1, 1, 1 return x, y, z def get_gyro(waittime): wait_process(waittime) x,y,z = 2,2,2 return x,y,z def get_accel(waittime): wait_process(waittime) x, y, z = 10, 10, 10 return x, y, z def get_liner_acc(waittime): wait_process(waittime) x, y, z = 1, 1, 1 return x, y, z def get_gravity(waittime): wait_process(waittime) x, y, z = 1, 1, 1 return x, y, z def get_quaternion(waittime): wait_process(waittime) w, x, y, z = 1, 1, 1, 1 return w, x, y, z def get_calib_status(waittime): wait_process(waittime) w, x, y, z = 3, 3, 3, 3 return w, x, y, z def single_process(waittime): start = time.time() get_gyro(waittime) end = time.time() print('elepsed_time:{0}[s]'.format(end-start)) def stream_process(waittime = 0.005): start = time.time() ex, ey, ez = get_euler(waittime) gx, gy, gz = get_gravity(waittime) ax, ay, az = get_accel(waittime) lax, lay, laz = get_liner_acc(waittime) rx, ry, rz = get_gyro(waittime) qw, qx, qy, qz = get_quaternion(waittime) a, b ,c, d = get_calib_status(waittime) end = time.time() print('elepsed_time:{0}[s]'.format(end-start)) return ex, ey, ez, gx, gy, gz, ax, ay, az, lax, lay, laz, rx, ry, rz, qw, qx, qy, qz, a, b, c, d def get_all_data(sensor, waittime=0.005): if sensor == 'euler': x, y, z = get_euler(waittime) return x, y, z elif sensor == 'gyro': x, y, z = get_gyro(waittime) return x,y,z elif sensor == 'linear_acc': x,y,z=get_liner_acc(waittime) return x,y,z elif sensor == 'gravity': x, y, z = get_gravity(waittime) return x,y,z elif sensor == 'acceleration': x, y, z = get_accel(waittime) return x, y, z elif sensor == 'quaternion': w, x, y, z = get_quaternion(waittime) return w, x, y, z elif sensor == 'calib_status': a, b, c, d = get_calib_status(waittime) return a, b, c, d else: pass def pararel_process(n): start = time.time() sensors = ['euler', 'gyro', 'gravity', 'acceleration', 'linear_acc', 'quaternion', 'calib_status'] result = [] with ThreadPoolExecutor(max_workers=n) as e: ret = e.map(get_all_data, sensors, chunksize=1) sms_multi = [r for r in ret] for res in sms_multi: for i in range(len(res)): result.append(res[i]) end = time.time() print('elepsed_time:{0}[s]'.format(end - start)) if __name__ == '__main__': waittime = 0.005# 実行時間の仮定 worker = 7 single_process(waittime)# シングル stream_process(waittime)# 直列処理 pararel_process(n=worker) # 並列処理
まだ回答がついていません
会員登録して回答してみよう