最後の章では、並行プログラミングのPython実装を学んだ - マルチスレッド。今日、我々は、進捗状況を別の並行プログラミングのPython実装--Asyncioを見て構築します。そして、前章のコルーチンが同じではないことを、このレッスンでは、我々は、原理の理解にもっと注意を払います。
レッスンを学習することによって、我々はの使用と比較すると、I / O操作中のことを知っているマルチスレッド通常のシングルスレッド、効率が大幅に改善されているので、なぜAsyncioそれを?
マルチスレッドには多くの利点があり、広く使用されているが、いくつかの制限がありますが。
※マルチスレッドプロセスはおそらく中断されるようにされて実行されている、それは場合に可能な競合状態があります
※特定のスレッド切り替え消費があり、マルチスレッド可能性が高い、高効率、高品質の要件を満たしていない、I / O操作は非常に集中されている場合、スレッドの数は無制限にすることができない増加。
これらの問題を解決するために、Asyncioはされて入ってきました。
Asyncioは何ですか?
同期VS非同期
まず、私たちはシンク(同期)の概念との非同期(非同期)を区別しましょう。
※同期いわゆる、操作を指し、次の操作が完了したら実行するために1を待つ必要があり、一つ一つを実行します。
アクションはブロックであり、プログラムが待機しませんが、あなたが実行できるアクションを識別し続ける場合※非同期は、交互に異なる操作を行うことができるものです。
簡単な例として、我々は報告を行うと、2つの方法で異なっているものを見るために上司に電子メールを送信する必要があります。
ソフトウェアとの同期方法によると、我々の入力データを※した後、その後、詳細なレポートを生成するために5分待って、書き込み電子メールは、所有者に送信
※また、非同期の方法に従って、敗者データの後、レポートを生成が始まったが、この時間は、私たち、この報告のためではなく、書き込み、電子メールに待って終了し、その他の詳細は後ほどレポート生成には、我々はレポートを表示するメッセージを書くために一時停止し、後で確認メッセージを知るために送信された書き込みを続けます。
作品Asyncio
同期および非同期ルーチンを理解し、我々はAsyncioそれが何であるかを最終的に、今日のテーマに戻りますか?
事実、Asyncioおよびその他のPythonプログラムでは、彼は唯一のメインスレッドを持っていた、シングルスレッドですが、悪質な行為異なるタスク(タスク)の数は、ここでタスクは特別なオブジェクト、これらの異なるタスクの未来にある、ありますオブジェクトは、イベントループ(イベントループ)制御と呼ばれています。私は、複数のスレッドのマルチスレッド版に例えここでのタスクを、置くことができます。
この問題の理解を簡単にするために、我々はそのタスクにのみ二つの状態を前提とすることができます:1つのレディ状態;しかし待ち状態を、レディ状態は現在アイドル状態が、実行する準備タスクを意味します。待機状態は、既に実行を意味するが、そのようなI / O操作と外部操作の完了を待っています。
、タスクレディ状態を選択する(具体的にタスクを選択し、それが待機する時間の長さ、等に関連する、リソースを占有);この場合、イベントループは、この2つの状態に対応する2つのタスクリストを維持しますこれまでに、教会のイベントループ制御にタスクまで実行します。
我々は、スレッドの安全性の問題を心配する必要はありませんので、それは、Asyncioの競合状態の場合は、オペレータは、発生しませんAsyncioのために、彼のタスクが動作中の外部要因によって中断されることはありません、その言及する価値があります。
Asyncioの使用状況
原則Asyncioは、我々は彼の使用法かどうかを確認するために、特定のコードと組み合わせて、終わりました。以上、例えば、以下の文言Asyncio(省略まだ例外処理)とサイト上のダウンロード可能なコンテンツでレッスン、より
輸入asyncio 輸入aiohttpの インポート時 非同期デフdownload_one(URL): セッションとしてaiohttp.ClientSessionと非同期(): RESPとしてsession.get(URL)と非同期: 印刷(' から読む{}を{} ' .format(resp.content_length、URL)) 非同期デフdownload_all(サイト): タスク = [asyncio.create_task(download_one(サイト))のためのサイトでのサイト] await asyncio.gather( * タスク) デフメイン(): サイト = [ ' https://en.wikipedia.org/wiki/Portal:Arts ' 、 ' https://en.wikipedia.org/wiki/Portal:History ' 、 " https://en.wikipedia.org/ウィキ/ポータル:社会' ' https://en.wikipedia.org/wiki/Portal:Biography ' ' https://en.wikipedia.org/wiki/Portal:Mathematics ' ' https://でアン。 wikipedia.org/wiki/Portal:Technology ' ' https://en.wikipedia.org/wiki/Portal:Geography ' 'https://en.wikipedia.org/wiki/Portal:Science ' ' https://en.wikipedia.org/wiki/Computer_science ' ' https://en.wikipedia.org/wiki/Python_(programming_language)' ' https://en.wikipedia.org/wiki/Java_(programming_language)' ' https://en.wikipedia.org/wiki/PHP ' ' https://en.wikipedia.org/wiki/ Node.jsの' ' https://en.wikipedia.org/wiki/The_C_Programming_Language ' ' https://en.wikipedia.org/wiki/Go_(programming_language)" ] START_TIME = time.perf_counter() asyncio.run(download_all(サイト)) END_TIME = time.perf_counter() プリント(' {}秒ダウン{}サイト' .format(LEN(サイト)、end_time- START_TIME)) もし __name__ == ' __main__ ' : メイン()
非同期とのawaitキーワードはここに最新の文言Asyncioで、この文/関数はイベントループの前で話すの概念に非ブロック、ちょうど相当する表現。タスクの実行待ちのプロセス場合は、待機リストに配置され、その後、タスクの状態リストに進みます。
asyncio.run(コロ)の主な機能は、最終的には近いイベントループAsyncioがルート呼び出し、それは彼が終了するまで、イベントループ、コロRUN入力を取得することを示している、と。実際には、asyncio.run()は、次の構文では、以前のバージョンと同等の、唯一のPython3.7 +の後に導入されます
ループ= asyncio.get_event_loop() のtry : loop.run_until_complete(コロ) 最終的には: loop.close()
Asyncioバージョン()、およびマルチスレッド化バージョンでdownload_allとしては大きな違いがあります前に:
タスク= [asyncio.create_task(download_one(サイト))のためのサイトでのサイト] await asyncio.gather( *タスク)
ここでasynco.creat_task(コア)、それはコルーチンの作成が彼の実行を手配するためにタスクを入力しコロ表し、このタスクオブジェクトを返します。また、この関数はPython3.7以降のバージョンであることは、以前のバージョンであれば、我々は次のように置き換えることができ、追加します。
asyncio.ensure_future(コロ)
私たちは、対応するタスクを作成して、ここで我々はすべてのサイトをダウンロードし、見ることができます。
その後見下す、asyncio.gather(* AWS、ループ=なし、return_exception = Falseが)、AWSがイベントループ内のすべてのタスクをシーケンス実行されています。もちろん、例で使用される多数の機能に加えて、Asyncioは、他の多くの用途を提供する、我々はできる、公式Pythonドキュメントを参照してください。
最後に、我々は完全にその利点を反映して、さらに高いよりも前に、このように効率の最終的な出力、マルチスレッドバージョンを見つけることができます。
Asyncio欠陥
前回の講義では、もちろんAsyncioの、いくつかの制限がありますが、同じことを、私たちは強いAsyncioを見ることができますが、プログラムの任意の種類は完璧ではありません。
実際の作業では、その強力な機能を果たしていることが特に良いAsyncioは、多くの場合、支持体として、適切なPythonライブラリを持っている必要があります十分に活用するために、我々は我々が使用しているマルチスレッドプログラミングの前で見たかもしれませんリクエストライブラリーが、その要求は、互換性のAsyncioライブラリではありませんので、ここでは、aiohttpライブラリを使用している、との互換性aiohttpライブラリ。
早期のpython3でAsyncioソフトウェアライブラリの互換性の問題が大きな問題となっていたが、技術の発展に伴い、この問題は徐々に解決されます。
なぜならスケジューリングタスクの面でより大きな自治の、Asyncioを使用した場合また、それ以外の場合はエラーになりやすいだろう、にもっと注意を払うために必要なコードを記述します。
私たちは一連の操作を待つ必要がある場合たとえば、使用asyncio.gathrer()を取った;それはおそらくそれにasyncio.waitを()を使用して、単一先物の場合。まあ、将来のために、私たちが必要とする彼がrun_until_complete()またはrun_forever()、について慎重に検討することです。ように、我々は考慮すべき具体的な課題に直面しています。
マルチスレッドやAsyncio?
私たちは、並行プログラミングの二つの方法は、我々はプログラミング方法の種類を選択し、実用的な問題が発生した、しかし、言われていますか?
来なきゃ、私たちは以下の仕様に従うことができます
※これは、I / Oがバインドされ、およびI / O操作が遅い、タスク/スレッドの相乗効果が、より適切な使用Asyncio、達成の多くを必要とする場合
※これは、I / Oは、その上に複数のスレッドを使用し、その後、すぐにタスクまたはスレッドの数は限られて結合したが、I / O操作された場合
それはCPUバウンドの場合※、あなたは運用効率を向上させるために複数のプロセスを必要とします。
概要
今日の研究では、一緒にAsyncioの原則と使用方法を学んAsyncioとマルチスレッドそれぞれの長所と短所を比較しました。
共通:
ある同時動作、マルチスレッド一つだけのスレッドが実行されている同じ時間を、そしてコルーチンを実行するための1つのタスクだけです。
相違点:マルチスレッドは、I / Oはスイッチングがオペレーティングシステムによって決定された場合、並列スレッドの効果を達成するために切り替えることにより、ブロックされた場合、開発者は心配する必要はありませんが、競合状態が発生します。
コルーチンは、一つのスレッドのみ、達成するために並行スレッドでタスクを切り替えの効果を遮断することにより、I / O時間、タイムスイッチは開発者によって決定されるもので、競合状態のない場合はありません。
マルチスレッド、Asyncioと異なるのは、彼は同時に複数の異なるタスクを実行し、マルチスレッドの自律制御よりも多く持つことができるように、シングルスレッドであるが、その内部機構の講義イベントループ。
タスクAsyncioの実行中に中断されることはありませんので、競合状態の場合は発生しません。特にどのようにI / O集中型の操作運転効率Asyncioはスイッチング損失スレッドが小さいよりも高くなる場合。そして、タスクAsyncioの数もスレッド数よりも、複数のスレッドを開くことができます。
しかし、多くの場合、Asyncioを使用して、ことに注意することは、特定のサポートの三者のライブラリを必要とし,,およびI / O操作が速く、ない重い場合、マルチスレッドの使用が効果的に問題を解決することができます。
質問
我々は2つの同時プログラミングのアイデアについて話している、並列プログラミングはまた、CPUの重いシーンに適しており、数回(マルチプロセッシング)を、言及されています
今需要がランダムな要素を指定し、入力Aリストで、この要素は、すべての整数の二乗に0から得られます。以下はプロセスの複数のバージョンが存在する場合、一般的な文言であるが、それを書くためにどのように?
インポート時 デフcpu_bound(番号): プリント(サム(私は* のために私に範囲(数))) デフcalculate_sum(番号): のための番号で番号: cpu_bound(数) デフメイン(): START_TIME = time.perf_counter() 番号 = [10000000 + X 用 X における範囲(20 )] calculate_sum(数字) END_TIME = time.perf_counter() プリント(' 計算takds {}秒' .format(end_time- START_TIME)) もし __name__ == ' __main__ ' : メイン()
演算結果(実行のみ掲載全期間)
計算takds 20.637497200000002秒
このアプローチではを見て
インポート時の インポートマルチプロセッシング デフcpu_bound(数): リターン・サム(私は* のために私に範囲(数)) デフfind_sums(数字): プールとしてmultiprocessing.Pool()を持ちます: pool.map(cpu_bound、数字) もし __name__ == ' __main__ ' : START_TIME = time.perf_counter() 番号 = [10000000 + X 用 X における範囲(20 )] find_sums(数字) END_TIME = time.perf_counter() プリント(' 計算takds {}秒' .format(END_TIME-START_TIME))
そして、最後の実行時間を見てみましょう
計算takds 7.3418618秒
コンピューティングの多くが必要とするので、マルチプロセスの使用は、プログラムの効率を改善する方法があります。