0
0

【python】restAPI実行でconcurrent.futuresを使ってみた

Last updated at Posted at 2022-04-08

はじめに

こんにちは。ジールの@________________-_です。

ネットワークアクセス処理にはマルチスレッド処理が有効という記事や本をよく見かけますが、
restAPIを利用してデータ送信する機会がありましたので、実験としてどの位速度が変わるのか計測してみました。
以下3つのパターンで比較しました。

  • マルチプロセス処理:concurrent.futures.ProcessPoolExecutorを利用。
  • マルチスレッド処理:concurrent.futures.ThreadPoolExecutorを利用。
  • 単純なループ処理:forループを利用。

環境

  • マシン:MacBook Pro 13inch 2020
  • CPU:2GHz Quad-Core intel Corei5
  • Mem:16GB

処理時間の計測

以下のコードを実行して、100回と1000回のリクエストで比較してみました。

import concurrent.futures
import time

import requests


def post_req():
    url = 'https://jsonplaceholder.typicode.com/posts'
    data = {'msg1': 'test_data1', 'msg2': 'test_data2', 'msg3': 'test_data3'}

    response = requests.post(url, json=data)

    return response.status_code


def process_pool(exec_cnt=1):
    start = time.perf_counter()

    with concurrent.futures.ProcessPoolExecutor() as executor:
        response_process = [executor.submit(post_req) for _ in range(exec_cnt)]

    success_cnt = 0
    error_cnt = 0
    for res in response_process:
        if res.result() == 201:
            success_cnt += 1
        else:
            error_cnt += 1

    print(f'process_success_cnt: {success_cnt}')
    print(f'process_error_cnt: {error_cnt}')
    print(f'process_duration: {time.perf_counter() - start}')


def thread_pool(exec_cnt=1):
    start = time.perf_counter()

    with concurrent.futures.ThreadPoolExecutor() as executor:
        response_process = [executor.submit(post_req) for _ in range(exec_cnt)]

    success_cnt = 0
    error_cnt = 0
    for res in response_process:
        if res.result() == 201:
            success_cnt += 1
        else:
            error_cnt += 1

    print(f'thread_success_cnt: {success_cnt}')
    print(f'thread_error_cnt: {error_cnt}')
    print(f'thread_duration: {time.perf_counter() - start}')


def normal_loop(exec_cnt=1):
    start = time.perf_counter()
    success_cnt = 0
    error_cnt = 0

    for _ in range(exec_cnt):
        res = post_req()
        if res == 201:
            success_cnt += 1
        else:
            error_cnt += 1

    print(f'normal_loop_success_cnt: {success_cnt}')
    print(f'normal_loop_error_cnt: {error_cnt}')
    print(f'normal_loop_duration: {time.perf_counter() - start}')


if __name__ == '__main__':
    exec_cnt = 100
    #exec_cnt = 1000
    print(f'exec_cnt: {exec_cnt}')

    print('-----start process-----')
    process_pool(exec_cnt)

    print('-----start thread-----')
    thread_pool(exec_cnt)

    print('-----start normal-----')
    normal_loop(exec_cnt)

結果

何回か実施しましたが、結果はほぼほぼ以下の通りでした。
どちらの場合もマルチスレッド処理が一番早いです。
マルチスレッドと通常のループ処理を比較すると10倍以上の差が出てます。

リクエスト100回の時

exec_cnt: 100
-----start process-----
process_success_cnt: 100
process_error_cnt: 0
process_duration: 6.557022245
-----start thread-----
thread_success_cnt: 100
thread_error_cnt: 0
thread_duration: 4.388986459999999
-----start normal-----
normal_loop_success_cnt: 100
normal_loop_error_cnt: 0
normal_loop_duration: 49.342961767000006

リクエスト1000回の時

exec_cnt: 1000
-----start process-----
process_success_cnt: 1000
process_error_cnt: 0
process_duration: 60.508084134
-----start thread-----
thread_success_cnt: 1000
thread_error_cnt: 0
thread_duration: 34.706618609
-----start normal-----
normal_loop_success_cnt: 1000
normal_loop_error_cnt: 0
normal_loop_duration: 480.41693989199996

おわりに

マルチスレッドと通常のループを比べるとこんなにも差が出るんですね!!!
10倍以上も差が出たのは驚きました。
マルチスレッドとマルチプロセスだと、マルチプロセスの方がオーバーヘッドが大きい分遅くなってます。
今回のような処理の場合は、マルチスレッドの利用はとても有効そうです!

参考

プロセスとスレッドの説明
詳細に説明されていてとても分かりやすいです。

concurrent.futuresの使い方


株式会社ジールでは、「ITリテラシーがない」「初期費用がかけられない」「親切・丁寧な支援がほしい」「ノーコード・ローコードがよい」「運用・保守の手間をかけられない」などのお客様の声を受けて、オールインワン型データ活用プラットフォーム「ZEUSCloud」を月額利用料にてご提供しております。
ご興味がある方は是非下記のリンクをご覧ください:

0
0
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
0