【Python3】requestsにthreadを使用すると非常に効果的
crawler,rest api等でrequestsにてgetを大量に投げる場合、ボトルネックになるのはI/Oバウンド。
入門Python3には以下の事が書いてる。
- スレッドはI/Oバウンド問題の解決のために使う。
- CPUバウンド問題では、プロセス、ネットワーキング、イベントを使う。
requests.get()している部分をworker threadとして切り離し、Queueにてタスクを管理するとかなり高速化できる。 計測結果とサンプルコードを記載する。
結果
requestsにて10回google検索結果を取得した結果。
タイプ | 総実行時間(sec) | response.elapsed合計値(sec) |
---|---|---|
thread | 0.6119930744171143 | 0:00:01.050656 |
non thread | 5.603970766067505 | 0:00:01.089367 |
9.3倍早く終る。素ん晴らしい!
総実行時間がresponse.elapsed合計値以下になってるのが感動する。
サンプルコード
non thread版
# non_thread.py import datetime import requests import time baseurl = "http://www.google.co.jp/search?hl=ja&q=" query_list = ['inu','neko','tori','sakana','kinoko','hebi','usagi','uma','hituzji','kabutomushi'] responses = [] start_time = time.time() for q in query_list: responses.append(requests.get(baseurl+q)) elapsed_time = time.time() - start_time print("total_time : {}".format(elapsed_time)) requests_time = datetime.timedelta() for r in responses: requests_time += r.elapsed print("requests_time : {}".format(requests_time))
thread版
# thread.py import datetime import queue import threading import requests import time def query_worker(query_queue): query = query_queue.get() responses.append(requests.get(baseurl + q)) query_queue.task_done() baseurl = "http://www.google.co.jp/search?hl=ja&q=" query_list = ['inu','neko','tori','sakana','kinoko','hebi','usagi','uma','hituzji','kabutomushi'] responses = [] # queueを設定 query_queue = queue.Queue() for q in query_list: query_queue.put(q) start_time = time.time() # Thread start while not query_queue.empty(): w_thread = threading.Thread(target=query_worker, args=(query_queue,)) w_thread.start() # wait all thread are ended. query_queue.join() # total running time elapsed_time = time.time() - start_time print("total_time : {}".format(elapsed_time)) # http response total time requests_time = datetime.timedelta() for r in responses: requests_time += r.elapsed print("requests_time : {}".format(requests_time))
参考
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
この本読みすぎてボロボロになってきた。
その他
PythonはGIL(グローバルインタープリタロック)が効いているのでCPUバウンド問題に対応するのにスレッド化は適さないので注意。逆に遅くなるよ!
あとはcrowlerを高速化しすぎてサーバーに怒られないように注意。
終わりに
高速化成功すると。気分いいですね。
並行処理、並列処理技術はめちゃめちゃ奥が深いので、まずは浅瀬で水浴びする程度から使っていきたい。
(おわり)
PythonでECサイトを作る(3)
コア処理修正。したけど、精度が落ちたので殆ど破棄。こういうこともある。
あとは相変わらず処理速度がくっそ遅い。なんとかしないと・・・。
対応策としては、プロセス分割すればいいのでは?とさっき思いついたので、明日ためそうと思う。
あとはサーバー構成検討し始めた。
GoogleCloudPratform使おうと思うけど、なんか入門する以前の状態で足踏みしてる感あり。正月ボケかなあ。
あまりCloud全般の知識がない感じだが、とりあえずHeroku的なPasSで良いと思うので、GoogleAppEngineを試してみよう。
(おわり)
PythonでECサイト作る(2)
主処理部分の改修してた、進捗悪い~。
やることリストも暴発仕掛けてるので、見直したい。
特に書けること無いので、ねよう。
loggerを使う(3)--完了
logging.confの[loggers]の名称にアンダーバーを使ってたら上手くいかなかったようだ。
名称を変えたらうまく行った。
あとは、log levelがError以上だったらslackに送るようにした。
slack連携はハマらず素直に動くのでいつも感動する。
なんでもかんでもSlackに入れてる人どうなん?と思ってたけど、ちょっと気持ちがわかってきた。
参考
終わりに
最近気づいたけど、Desktop版Slackめちゃめちゃメモリ使うのね…。いいけど。
loggerを使う(2)
公式のHowToをまぁまぁ読んだ。全てのprint文の置き換えと、config化した。
システムのconfigと、bs4用configとlogger用configがあり、projectのRoot Directoryがごちゃごちゃしてきたので整理した。
…今度はDirectoryが多い…。
参考
公式
Logging HOWTO — Python 3.5.2 ドキュメント
config化参考
課題
logging.confファイルの設定がいまいち効いてないような?
表示レベルをDebugに設定しているのにInfoレベルまで表示されている。
サブモジュール内のloggerが上手く行ってるのかデバッグする必要あり。
loggerを使う(1)
print文仕込みマンだったけど、コードの規模が大きくなってきた。
loggerを使っていこう。
と思って調べたら、怒れる人が居て怖い。
怒れる記事
知識0でこの記事をよんでも何に怒りを感じているか全然わからなかった。
?
参考
簡単な概念。
st-president-program.seesaa.net
ログレベルとフィルター。出力先の操作ができる。
簡単な使い方。
Python loggingモジュールの基本的な使い方 - Symfoware
簡単。
公式の丁寧なHOWTO
Logging HOWTO — Python 3.5.2 ドキュメント
今は流し読み。
(2)の記事で頑張ろう。
ルートロガーを使用すると他人のロガーに影響あり
ここまで読んで、ようやく冒頭の記事の怒りの内容がわかってきた。
基本作法としてgetLoger(__name__)
を忘れなければ良さそう。
実践する
入門30分なので、高度にloggerを使いこなせそうにない。
とりあえず、標準出力、ファイル出力、ログレベル設定を気にしながらソースに仕込んでいこう。
さてさて、logger設定をconfigと連携させる必要あるかな?…あるなー。
面倒だが、やろう。
BeautifulSoup4で全ての文字を書き換える
タグを辿って、tag.stringの書き換えを繰り返すと、NavigableStringは書き換え不可能!と怒られた。ごめん。
公式documentをよく読んだら、replace_with()
つかえとのこと。
teratailに質問もいいけど、公式ドキュメントも読もう。うん。
参考
BeautifulSoup公式
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation
実装例
BeautifulSoup4 TreeNode traverse and fix Navigable ...