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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

Q&A

1回答

1925閲覧

[python] 並列処理の動作が3回に1回程度、遅くなる理由が分かりません。

hirokuro900

総合スコア33

並列処理

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

selenium

Selenium(セレニウム)は、ブラウザをプログラムで作動させるフレームワークです。この原理を使うことにより、ブラウザのユーザーテストなどを自動化にすることができます。

0グッド

0クリップ

投稿2020/11/26 10:16

concurrent.futures を使用した並列処理(非同期処理?)で3回に1回くらいの割合で動作が重たくなります。

処理の流れを簡易的に書きます

  1. 会社四季報のサイトへアクセス
  2. 特定の情報を抽出
  3. 必要な情報のみに整形
  4. データフレームに格納
  5. csvファイルに書き込み

とゆう流れです。
requestsではhtmlを取得できなかったので、seleniumを使用しています。

経過時間はこんな感じです。(スレッド別に実験しているのでその他の結果は下記に記述しています。)
1, 15.708
2, 31.406
3, 11.567
4, 11.047
5, 38.353

上記の試行回数 5 回の内、2回は倍近くの時間がかかっています。下記に記載しているスレッド数を変更して実験した結果もほぼ同じ結果になっています。
なぜ、時間が遅くなるのか分かりません。
どなたか教えていただけないでしょうか?

コードの実行は下記のように行います。

python

1# リストに銘柄コードを記述 2brand_code = [2440, 2445, 2449, 2453, 2454] 3parallel(brand_code)

コードはこちらです。

python

1from bs4 import BeautifulSoup as bs 2import pandas as pd 3import requests 4import lxml 5import re 6 7# ファイルのパスを調べる 8import os 9import datetime 10 11from selenium import webdriver 12from webdriver_manager.chrome import ChromeDriverManager 13import time 14 15# 非同期処理 16import concurrent.futures 17 18def op(): 19 """seleniumでhtmlを取得する 20 21 requestsで要素を取得できない場合にこちらを実行する 22 """ 23 options = webdriver.ChromeOptions() 24# userdata_dir = 'C://chrome_profile' # C直下 25 26 options.add_argument("start-maximized") # ウィンドウの最大化 27 options.add_argument('--disable-extensions') # エクステンション無効 28 options.add_argument("--disable-dev-shm-usage") # シェアドメモリの保持場所が/dev/shm => /tmp(安定する?) 29 30 # ヘッドレスモードのハッピーセット.. 31 options.add_argument("--headless") 32 options.add_argument("--no-sandbox") 33 options.add_argument("--disable-browser-side-navigation") 34 options.add_argument("--disable-gpu") 35 36 # プロファイルの確認 37# if os.path.isdir(userdata_dir): 38# options.add_argument('--user-data-dir=' + userdata_dir) 39# else: 40# os.makedirs(userdata_dir, exist_ok=True) 41# options.add_argument('--user-data-dir=' + userdata_dir) 42 43 # 通知を無効にする 44 prefs = {"profile.default_content_setting_values.notifications" : 2} # https://stackoverflow.com/questions/41400934/ 45 options.add_experimental_option("prefs", prefs) 46 # 上部のバー「自動制御中です」を非表示にする 47 options.add_experimental_option("excludeSwitches", ['enable-automation']); 48 49 driver = webdriver.Chrome(ChromeDriverManager().install(), options=options) 50 51 return driver 52 53################################################## 54 55def crawl(code): 56 57 try: 58 driver = op() 59 url = 'https://shikiho.jp/stocks/' + str(code) 60 driver.get(url) 61 # 安定重視、読み込み完了を効率的する 62 time.sleep(3) 63 64 html = driver.page_source.encode('utf-8') 65 driver.quit() 66 67 try: 68 soup = bs(html, "lxml") 69 except: 70 soup = bs(html, "html.parser") 71 72 # 業績エリアの大枠を指定 73 if soup.find(class_="matrix"): 74 section = soup.find(class_="matrix") 75 # 個別に要素を抽出 76 if section.find_all(class_="default"): 77 items = section.find_all(class_="default") 78 79 # 企業名、上場年を抽出 80 if soup.find(class_="name"): 81 comp_name = soup.find(class_="name").text 82 else: 83 comp_name = code 84 listed = soup.find(class_="block cfx").find('dd').text 85 86 # 決算情報でデータがある箇所を抽出 87 perf = [] 88 for item in items: 89 if re.search(r'^連[1-9]{2}.[1-9]{,2}\s[1-9]{,3}', item.text): 90 perf.append(item.text) 91 92 Settlement = [] # 決算月 93 sales = [] # 売上高 94 opin = [] # 営業利益 95 netin = [] # 純利益 96 oneprofit = [] # 1株益 97 onediv = [] # 1株配 98 99 for indiv in perf: 100 sp = indiv.split(' ') 101 if sp[0]: 102 Settlement.append(sp[0]) 103 else: 104 Settlement.append(0) 105 if sp[1]: 106 sales.append(sp[1]) 107 else: 108 sales.append(0) 109 if sp[2]: 110 opin.append(sp[2]) 111 else: 112 opin.append(0) 113 if sp[4]: 114 netin.append(sp[4]) 115 else: 116 netin.append(0) 117 if sp[5]: 118 oneprofit.append(sp[5]) 119 else: 120 oneprofit.append(0) 121 if sp[6]: 122 onediv.append(sp[6]) 123 else: 124 onediv.append(0) 125 126 value = { 127 '企業名' :comp_name, 128 '銘柄コード':code, 129 '上場年' :listed, 130 '決済年' :Settlement, 131 '売上高' :sales, 132 '営業利益' :opin, 133 '純利益' :netin, 134 '1株益' :oneprofit, 135 '1株配' :onediv 136 } 137 138 df = pd.DataFrame(value) 139 return df 140 else: 141 return code 142 else: 143 return code 144 except Exception as e: 145 print(code, e) 146 pass 147 148def parallel(brand_code): 149 """並列処理 150 151 パソコンへの負荷を考えると3つの処理を6スレッドで実行するのが効率的 152 """ 153 # 時間測定スタート 154 ts = time.perf_counter() 155 156 csv = pd.read_csv('data/stock_price_first.csv', encoding="shift-jis") 157 max_workers = 6 158 with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: 159 futures = [executor.submit(crawl, code)for code in brand_code] 160 161 ng_code = [] 162 for i, future in enumerate(concurrent.futures.as_completed(futures)): 163 if type(future.result()) is pd.core.frame.DataFrame: 164 csv = csv.append(future.result(), ignore_index=True) 165 print(f'\r{i+1}処理中..\n', end='') 166 else: 167 ng_code.append(future.result()) 168 169 print('終了しました♪\n取得不可コード → '+str(ng_code)) 170 csv.to_csv('data/stock_price_first.csv', index=False, encoding="shift-jis") 171 172 td = time.perf_counter() 173 print(round((td - ts), 3))

実験結果です。

python

1計測時間測定 25銘柄の情報を取得するテスト 3 41Thread 51, 42.419 62, 27.715 73, 54.995 84, 31.309 95, 50.37 10mean : 41.362 11 122Thread 131, 16.757 142, 24.572 153, 16.718 164, 18.627 175, 35.863 18mean : 22.51 19 203Thread 211, 15.708 222, 31.406 233, 11.567 244, 11.047 255, 38.353 26mean : 21.62 27 284Thread 291, 10.812 302, 31.905 313, 11.247 324, 11.483 335, 38.787 34mean : 20.85 35 365Thread 371, 5.816 382, 32.761 393, 6.193 404, 5.798 415, 36.418 42mean : 17.4 43 446Thread 451, 6.184 462, 6.557 473, 36.056 484, 5.988 495, 5.751 50mean : 12.11 51 527Thread 531, 36.037 542, 5.896 553, 5.94 564, 38.025 575, 5.796 58mean : 18.34 59 608Thread 611, 5.802 622, 34.36 633, 6.652 644, 5.567 655, 36.327 66mean : 17.74 67 689Thread 691, 5.784 702, 5.62 713, 35.45 724, 7.162 735, 5.472 74 7510Thread 761, 5.338 772, 7.352 783, 53.905 794, 5.587 805, 5.409 81

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

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

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

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

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

rysh

2020/11/27 02:33

使っているPCのCPUのコア数は幾つですか?
hirokuro900

2020/11/27 02:37

コメントありがとうございます。 タスクマネージャで確認しましたところ、 コア数 : 10 論理プロセッサ数 20 となっております。
guest

回答1

0

リクエスト先のサーバーが付加対策のためか攻撃防止のためかわからないですが、レスポンスを遅くしているんじゃ無いかと思います。
HTML取得部分とパース部分をわけてHTMLはファイルとして保存しておくようにすると効率がよくなるかと思います。

こちらの本にそう言ったテクニックなどいろいろ乗っていました

分けた部分でそれぞれ時間を計測したり、Sleepをもっと長くしたりしても原因を特定する鍵になるかもしれません。

投稿2020/11/27 03:55

編集2020/11/27 03:56
rysh

総合スコア874

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

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

hirokuro900

2020/11/27 04:01

コメントありがとうございます。 ご紹介していただいた本、即購入いたしました。 ご提案していただい方法などを考慮して、プロセスを細かくして思考錯誤してみます! 原因が判明次第こちらに記述いたします。 貴重なお時間を割いていただき感謝しております。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問