LoginSignup
0
1

繰り返し処理と並列処理の簡単な比較

Posted at

はじめに

ある処理について、複数回の実行を要する場面があります。このとき、処理間の前後関係に制約がない場合は、繰り返し処理(for文やwhile文)や並列処理がその実現方法として挙げられます。今回は、繰り返し処理と並列処理の簡単な比較として、コードと実行時間の違いについて紹介します。

以降に挙げる例はGoogle Colaboratory1で実行しています。

複数回の実行を要する処理の例

複数回の実行を要する処理の例
import random
import time


def process(num):
    """
    本記事におけるある処理。
    ある程度の時間がかかる処理と仮定し、1msの一時停止をした後にランダムな数値を出力する。
    """
    time.sleep(0.001)
    random.seed(num)
    return num, random.random()

繰り返し処理の例

繰り返し処理の例+時間計測
%%timeit

if __name__ == "__main__":
    nums = range(1, 1_001)
    results = []
    for num in nums:
        result = process(num)
        results.append(result)
1.13 s ± 7.37 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

並列処理の例

今回、並列処理はconcurrent.futures.ProcessPoolExecutor2というクラス(以降、ProcessPoolExecutor)により実現させます。

今回の実行環境において、利用可能なCPUのコア数は2となります。

実行環境における利用可能なCPUのコア数の確認
import os


os.cpu_count()
2

ProcessPoolExecutorで指定する並列数は、そのまま利用可能なCPUのコア数(2)とします。

並列処理の例+時間計測
%%timeit

import concurrent.futures


if __name__ == "__main__":
    nums = range(1, 1_001)
    results = []
    with concurrent.futures.ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
        futures = [executor.submit(process, num) for num in nums]
        for future in concurrent.futures.as_completed(futures):
            if future.exception():
                raise Exception(f"{future.exception()}")
            else:
                results.append(future.result())
702 ms ± 17.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

実行時間について、繰り返し処理では平均で1.13msでしたが、並列処理の場合は平均で702msでした。つまり、今回の例においては、繰り返し処理を並列処理に書き換えることによって、実行時間の短縮という恩恵が得られます。

今回の例に基づいて、繰り返し処理から並列処理に書き換える場合の差分は以下となります。

差分(繰り返し処理から並列処理に書き換える場合)
+ import concurrent.futures
+
+
  if __name__ == "__main__":
      nums = range(1, 1_001)
      results = []
-     for num in nums:
-         result = process(num)
-         results.append(result)
+     with concurrent.futures.ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
+         futures = [executor.submit(process, num) for num in data]
+         for future in concurrent.futures.as_completed(futures):
+             if future.exception():
+                 raise Exception(f"{future.exception()}")
+             else:
+                 results.append(future.result())

まとめ

繰り返し処理と並列処理の簡単な比較として、コードと実行時間の違いについて紹介しました。今回の例においては、実行時間の観点で、並列処理の方が優れていました。ただ、要件や制約によってどちらが望ましいかが変わるため、それらの整理や計測を踏まえて判断することを推奨します。

  1. https://colab.google/

  2. https://docs.python.org/ja/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1