I.はじめに
何回した後、私たちは非常に重要なポイントがクロールされるスピードのある場所を、改善するために多くのことを見つけるの要件を達成するために、爬虫類を書きました。この記事では、クロール速度を向上させるために、マルチプロセス、マルチスレッド、コルーチンを通じてコードを使用する方法について説明します。注意:私たちはあなたのコード内の理論と原則、すべてのものへの洞察をしません。
第二に、同期
まず、我々は簡略爬虫類、各機能セグメント、意識行動関数型プログラミングを書き込みます。次のコードは、アクセスオブジェクト300 Baiduのページであり、機能が設定parse_1サイクル、(0から始まる)現在のサイクル数と受信したURLのparse_2関数の各サイクルであっても良い、ステータスコードを返します。
インポート要求
デフparse_1():
URL = 'https://www.baidu.com'
(300)の範囲内のiについて:
parse_2(URL)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
シングルスレッドモードを使用して、リクエストURLが必然的に待ち時間につながる場合、パフォーマンスは主に、IO要求で消費されます
サンプル・コードは、一般的なシリアル・ロジックで、parse_1はURLとparse_2、parse_2要求及びステータスコードparse_1ステップを反復継続戻るまでのサイクル数を通過する前にもう一度繰り返しました
第三に、マルチスレッド
プロセスが実際に改善されたCPU使用率が得られる使用量を増加させるマルチスレッドので、プログラムの実装では、各スケール上の唯一のスレッドCPU時間があるため
マルチスレッドライブラリがの多くを持って、ここに証明するためにThreadPoolExecutorでconcurrent.futures。はじめにThreadPoolExecutorライブラリは他のライブラリのコードよりも簡潔であるため、
説明の便宜のために、それは新たに部品を追加された場合、次のコードは、コードの最初の行はプラス>シンボルは、説明の観察を容易にする、実際の操作が必要で除去します
インポート要求
> concurrent.futuresインポートThreadPoolExecutorから
デフparse_1():
URL = 'https://www.baidu.com'
#スレッドプールを作成します。
>プール= ThreadPoolExecutor(6)
(300)の範囲内のiについて:
> pool.submit(parse_2、URL)
> pool.shutdown(待機= TRUE)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
同期は相対的とは非同期です。非同期は、互いに独立して、イベントを待っている間に自分のことをし続ける、あなたが作業の完了後に、このイベントを待つ必要はありません。非同期スレッドは時々我々はあなたがコールバックを使用することができ、結果を知っている必要があり、その結果を知らない非同期処理非同期のマルチスレッド手段である方法を、達成することです
インポート要求
concurrent.futuresインポートThreadPoolExecutorから
#コールバック関数を追加します。
> DEFコールバック(未来):
>印刷(future.result())
デフparse_1():
URL = 'https://www.baidu.com'
プール= ThreadPoolExecutor(6)
(300)の範囲内のiについて:
>結果= pool.submit(parse_2、URL)
#コールバックの重要なステップ
> results.add_done_callback(コールバック)
pool.shutdown(待機= TRUE)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
Pはython無数の人々はGIL(グローバルインタプリタロック)を批判しているマルチスレッドが、IO集約型のマルチスレッドタスクに属しても、この大多数のページをクロールするために非常に適しています。
第四に、マルチプロセス
マルチプロセスは、2つの方法で実装:ProcessPoolExecutorとマルチプロセッシング
1. ProcessPoolExecutor
そして、同様のマルチスレッドThreadPoolExecutor
インポート要求
> concurrent.futuresからProcessPoolExecutorをインポート
デフparse_1():
URL = 'https://www.baidu.com'
#スレッドプールを作成します。
>プール= ProcessPoolExecutor(6)
(300)の範囲内のiについて:
> pool.submit(parse_2、URL)
> pool.shutdown(待機= TRUE)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
2つのクラス名の変更を探し、コードはまだ非常にシンプルで、共感もコールバック関数を追加することができます
インポート要求
concurrent.futuresインポートProcessPoolExecutorから
> DEFコールバック(未来):
>印刷(future.result())
デフparse_1():
URL = 'https://www.baidu.com'
プール= ProcessPoolExecutor(6)
(300)の範囲内のiについて:
>結果= pool.submit(parse_2、URL)
> results.add_done_callback(コールバック)
pool.shutdown(待機= TRUE)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
2.マルチプロセッシング
コードで直接見て、コメント内のすべて。
インポート要求
>インポートプールをマルチプロセッシングから
デフparse_1():
URL = 'https://www.baidu.com'
#内蔵プール
>プール=プール(プロセス= 5)
#ストア結果
> res_lst = []
(300)の範囲内のiについて:
#タスクプールに参加
> RES = pool.apply_async(FUNC = parse_2、引数=(URL))
#取得結果は完了し(削除する必要があります)
> res_lst.append(RES)
#最終結果を格納し(直接または印刷保存することができます)
> good_res_lst = []
> res_lstでの解像度のための:
#取得プロセスを使用した後の結果を取得します
> good_res = res.get()
#判定結果が良いか悪いですか
> good_res場合:
> good_res_lst.append(good_res)
#電源をオフにし、完了を待ちます
> pool.close()
> pool.join()
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
あなたは、コードマルチプロセッシングライブラリーを少し面倒を見るが、より多くの拡大を支援することができます。マルチプロセスとマルチスレッドは本当に加速の目的を達成することができますが、彼らはIOスレッドやプロセスをブロックしている場合は、廃棄物となりますので、より良い方法があります......
第五に、非ブロック非同期
コルーチン+コールバック我々は目的を達成することができ、ダイナミック、ノンブロッキングの非同期のコラボレーションで、自然はとても資源の大規模な範囲での使用に、一つのスレッドだけを取りました
クラシックは、非同期良く、非同期の非ブロッキングをよりよく理解asyncioライブラリを理解するためには、より上位のパッケージaiohttpの漸進的な出現の使用を容易にするために、ライブラリー+収率asyncio非ブロックの使用です。そしてgeventはコルーチンライブラリを実装するのは非常に簡単です
インポート要求
> gevent輸入サルから
#猿の魂のパッチが共同で実行されます
> monkey.patch_all()
>インポート行商しました
デフparse_1():
URL = 'https://www.baidu.com'
#タスクリストを作成します。
> tasks_list = []
(300)の範囲内のiについて:
>タスク= gevent.spawn(parse_2、URL)
> tasks_list.append(タスク)
> gevent.joinall(tasks_list)
デフparse_2(URL):
応答= requests.get(URL)
印刷(response.status_code)
__name__ == '__main__' の場合:
parse_1()
geventが大幅にスピード、また新たな問題を紹介することができます。私たちは、サーバー上であまりにも多くの負担を引き起こすことが速すぎたくない場合はどのように行うには?それは、マルチプロセス、マルチスレッド化ビルドプールされている場合は、プールの数を制御することができます。ビルドキュー:あなたはgeventと速度を制御したい場合にも良い方法があります。geventはまた、以下のコードより大きな変化をQueneクラスを提供しました
インポート要求
gevent輸入サルから
monkey.patch_all()
インポートは行商しました
> gevent.queueインポートキューから
デフparse_1():
URL = 'https://www.baidu.com'
tasks_list = []
#インスタンス化キュー
> quene =キュー()
(300)の範囲内のiについて:
すべてのキューは、URL#を押します
> quene.put_nowait(URL)
二つのキュー#
> _ための範囲内(2):
>タスク= gevent.spawn(parse_2)
> tasks_list.append(タスク)
gevent.joinall(tasks_list)
#私たちは、キューにある、パラメータを渡す必要はありません。
> DEF parse_2():
#サイクルは、キューが空であるかどうか
>しばらくないquene.empty():
#ポップキュー
> URL = quene.get_nowait()
応答= requests.get(URL)
分析キューのステータス#
>印刷(quene.qsize()、response.status_code)
__name__ == '__main__' の場合:
parse_1()
結論
これらは、いくつかの一般的に使用される加速方法です。あなたはタイムコード・テスト・モジュールを利用することができる興味を持っている場合は、実行時間を決定します。〜さようなら、サーバーに過度の圧力を与えていない、爬虫類は重要なスキルですが、速度が適切に良い習慣爬虫類の労働者を制御して加速
もっと楽しく、コードケース加法群:850591259