【非同期処理】Pythonの async / await 構文を使ってみよう!
Summary
TLDRこのビデオはPythonの非同期処理について解説しています。非同期処理とは処理の完了を待たずに別の処理を実行できる機能で、入出力処理などにおいて効果的です。ビデオではasyncioモジュールを使った非同期処理の基本的なコードの書き方と、タスクの並列実行、ギャザーによる複数の戻り値の取得などについて解説しています。そして実際にAzureファイルストレージからのファイルダウンロードを例にとって、非同期処理の実践的な利用法も紹介しています。
Takeaways
- 😀 非同期処理とは、処理の完了を待たずに別の処理を実行できること
- 😊 入出力に時間のかかる処理で非同期処理を利用することが多い
- 🤔 非同期処理は並列処理とは異なり、イベントループによって制御される
- 😯 コルーチンは処理を中断し、後から再開できる関数
- 😃 awaitでコルーチンを呼び出し、完了まで待つことができる
- 🙂 create_taskでタスクを生成し、複数のコルーチンを並列実行できる
- 🧐 gatherで複数のタスクやコルーチンをまとめて呼び出せる
- 🤩 run_in_executorで普通の関数を非同期処理として扱える
- 😮 wait_forでタイムアウトを設定し、処理を強制終了できる
- 👍 Azure SDKのような非同期ライブラリも扱える
Q & A
非同期処理とは何ですか?
-非同期処理とは、処理の完了を待たずに別の処理を並行して走らせることです。I/Oバウンドな処理で時間がかかる場合に利用されます。
非同期処理と並列処理はどう違うのですか?
-非同期処理は並列処理を簡単に扱えるようにしたものです。イベントループがタスクを制御してくれるので、細かいことを気にせずに並列処理を記述できます。
コルーチンとは何ですか?
-コルーチンとは、処理を途中で中断して後から再開できる関数のことです。非同期処理で利用されます。
なぜasyncioのsleepを使うのですか?
-asyncioのsleepはコルーチンなので、非同期処理でawaitできます。時間モジュールのsleepはコルーチンではないのでエラーになります。
gatherはどういう場合に使いますか?
-gatherは複数のコルーチンやタスクを平行実行し、それぞれの戻り値をまとめて受け取るために使います。平行処理結果を一度に取得したい時に利用します。
タスクとは何ですか?
-タスクはコルーチンをラップしたもので、これを使うことでコルーチンを平行処理できます。create_taskでタスクを生成します。
実際にファイルダウンロードで非同期処理を使うメリットは何ですか?
-ダウンロード処理に時間がかかる場合、逐次処理だとプログラム全体がブロックされます。非同期処理を使えば他の処理を並行で走らせられるので効率的です。
普通の関数を非同期処理で使うにはどうすればいいですか?
-loop.run_in_executorで指定した関数を非同期処理で使えるようにラップできます。スレッドプールやプロセスプールも指定できます。
タイムアウトを設定するにはどうしたらいいですか?
-asyncio.wait_forを使うと、指定した時間を超えたらタイムアウト例外を送出できます。長時間処理を強制終了させたい場合に利用します。
Windowsで実行する時の注意点は何ですか?
-Windowsの場合はイベントループポリシーをWindowsSelectorEventLoopPolicyに設定する必要があるようです。バグ回避のためです。
Outlines
🐍 Pythonの非同期処理入門
佐藤は非同期処理の基本として、特定のライブラリ使用時に必要になるPythonのasync/awaitについて解説します。この動画は非同期処理を扱うフレームワークやライブラリの開発者ではなく、非同期処理を使えるようになることを目指すアプリケーション開発者向けです。非同期処理とは、処理の完了を待たずに別の処理を走らせることで、IOバウンドの操作で時間がかかる場合に有用です。非同期処理は並列処理や並行処理とは異なり、イベントループを使って非同期タスクを効率よく制御します。
🔧 非同期処理の基本コード例
async/await構文の基本的な使い方を説明し、非同期処理のコード例を示します。コルーチンを実行するためにはawaitキーワードを使い、処理の完了を待つことができます。非同期処理では、処理の完了を待ちつつ、別の処理も同時に行うことが可能です。この柔軟性により、例えば1秒と2秒のスリープを非同期で実行するコードを通じて、非同期処理の動作を確認します。また、関数から非同期処理を呼び出す際にも、その関数はコルーチンである必要があり、戻り値の扱い方についても説明します。
🚀 非同期処理の高度な使い方
非同期処理を平行処理で動かす方法として、タスクの作成とギャザー関数の使用を紹介します。タスクを作ることでコルーチンをラップし、平行処理を可能にします。また、ギャザーを使うことで複数のコルーチンやタスクを平行処理し、その結果を一度に受け取ることができます。さらに、非同期処理で普通の関数を扱いたい場合のrun_in_executorの使い方や、処理のタイムアウトを設定する方法についても解説します。これらの高度な機能を使いこなすことで、より複雑な非同期プログラムを効率良く実行することが可能になります。
🌐 実践!非同期ファイルダウンロード
実際のアプリケーション例として、Azureクラウドサービスからファイルを非同期でダウンロードする処理を紹介します。非同期対応のライブラリを使用することで、複数のファイルを同時にダウンロードすることが可能です。これにより、ファイルサイズが大きい場合でも効率的に処理を行うことができます。Windows環境での特別な設定にも触れ、非同期処理の実用例を通して、async/awaitの扱い方を深く理解することを目指します。
Mindmap
Keywords
💡非同期処理
💡コルーチン
💡イベントループ
💡アウェイト
💡タスク
💡Gather
💡ランインエグゼキューター
💡タイムアウト
💡Azure
💡イベント駆動型
Highlights
非同期処理とは、処理の完了を待たずに別の処理を並行して実行できる
非同期処理は入出力に時間のかかる処理でよく使われる
非同期処理はイベントループを使ってタスクを制御する
コルーチンは処理を途中で中断して後から再開できる
アウェイトでコルーチンを呼び出すと処理完了を待つことができる
タスクを使うとコルーチンを並列処理で実行できる
ギャザーで複数のコルーチンやタスクの結果をまとめて取得できる
ランインエグゼキューターで普通の関数を非同期処理で呼び出せる
ウェイトフォーでタイムアウトを設定して処理を強制終了できる
Azure SDKのファイルダウンロードが非同期対応なのでアウェイトで呼び出せる
Windowsではイベントループポリシーの設定が必要な場合がある
非同期ライブラリを扱う時はアウェイトで呼び出せるか確認する
コルーチンとアウェイトを使うことで並列処理が扱いやすくなる
タスクやギャザーを組み合わせることで複雑な並列処理が実装できる
非同期処理は平行性を上手く利用するための仕組みだと理解する
Transcripts
こんにちはタイソンvtuberの佐藤
です今回はPythonの非同期処理
エンシングアウェイトについて解説したい
と思いますエイシングアウェイトハイソン
で使う頻度が多いとは言えませんが特定の
ライブラリを使う時とかに必要になること
があるのでこの機会にぜひ使い方を覚えて
みてくださいこのチャンネルは
Pythonに関する情報を発信している
ので
良ければチャンネル登録よろしくお願いし
ますまたメンバーシップ会員しか見れない
動画ライブもあるので
良ければメンバーシップのご検討も
よろしくお願いします
まずはじめにこの動画の目的について
あらかじめご説明しておきますこの動画は
非同期処理を使ったフレームワークや
ライブラリの開発者向けには作られてい
ませんアプリケーション開発の中で
非同期処理を扱ったフレームワーク
ライブラリを使えるようになることを目的
としたエンジニア向けに作ってるのでその
点あらかじめご了承くださいでは
非同期処理って何かってことなんですが
非同期処理というのは
処理の完了を待たずに別の処理を走らせる
ことを言います一般的なPython
コードは前の処理が完了したら次の処理が
実行されますよねこういうのを逐次処理と
言います
一方非同期処理は
処理の完了を待たずに別の処理を走らせる
ことができるため普通のプログラムよりも
複雑なことができますそして
非同期処理を扱いたい時に使用するのが
ACTAway投稿文ですじゃあどんな時
に非同期処理を使うかっていうと
処理が
完了するまでに時間がかかるなーって時に
非同期処理を使います特にPythonで
は
IOバウンドつまり入出力に関わる書類に
おいて時間がかかるなって時に
非同期処理を使うことが多いです例えば
ファイルのダウンロードやアップロードや
データベースの読み書きこういった処理で
データ数やファイルサイズが大きいとこの
処理時間がかかるんだよなーって時に
Pythonでは非同期処理が使われる
ことが多いですねここまでの話を聞いて
処理の完了を待たずに別の処理を走らせる
移動機処理ってそれ
並列処理平行処理と同じなんじゃない何が
違うんだと思った人もいるんじゃないのか
なと思います
並列処理並行処理については以前に動画を
アップのねわからない方はぜひそちらを見
てみてください実は
非同期処理はそもそも平行処理や並列処理
とは
違うっていうわけじゃなくて平行処理と
いうものを簡単に扱えるようにしたのが非
同期処理だよっていうことです特に非同期
処理ではイベントループっていうものが
登場してこのイベントループが
非同期のタスクをいい感じに制御してくれ
ますなので私たちは細かいことを考えずに
あこれは処理の完了を待たなくていいやつ
ですあこっちは処理の完了を混ぜたやつ
ですねって感じで簡単なコードで平行処理
を扱うことができます言葉だけ説明してい
てもいまいちイメージがつきにくいかなと
思うので
絶縁しながら非同期処理のコードの書き方
を解説していきますねまたこれから先で
解説するコードは
iPhone3.7以上じゃないと動か
ないので
バージョンが低い方はPythonの
バージョンアップをお願いします
はじめに
レーシングアウェイト構文を扱うための
Python標準モジュールathing
i/Oをインポートしますでこんなメイン
関数があったとしますこの関数はこの
スクリプトが実行されて一番初めに呼ば
れる関数になりますそしてこのスクリプト
の中で
非同期処理を扱いたいのでこのメイン関数
の定義の前にシンクってつけますいい
シンクをつけた関数はコルーチンという
ものになりますコルチとは
処理をある場所で一次中断してまた途中
から再開できるものを言います今この
メインでは中断する部分はありませんね
後ほど書いていきますそしてこの
スクリプトを実行した時に動く
ifネーム=メインの中でシンクIO
Runmainっていう風に書いておき
ます
はイベントループが作られて引数に指定し
たコルーチンが実行されます
それではメインの中で
完了までに時間がかかる処理を呼び出し
たいと思いますまずコードがシンプルな方
が分かりやすいと思うのでシンク
IOのスリープを呼び出そうと思います
スリープだとイメージがつきにくいかも
しれませんがこの部分が何かしらの時間が
かかる処理例えばファイルのダウンロード
とかだと思ってください
ちなみに
普段スリープを使うときはタイム
モジュールのスリーブを使ってると思うん
ですが今回はAsyncioのスリップを
使いますなぜかって言うとシンクIOの
スリーブがコルチにだからですエディター
でこのスリープの部分の定義にジャンプし
てみると
Fの前にエーシンクってついてるのでこの
スリープがコルーチンであることがわかり
ます
タイムモジュールのスリープは普通の関数
なのでそのままではエーシンクアウェイト
構文で扱うことができないんですよねで
スリープの引数にスリープさせたい秒数を
渡します今回は1秒のスリープと2秒の
スリープを1回ずつ実行しようと思います
そして注意が必要なのはコルーチンはただ
このように書いただけでは動きません
コルチを実行するにはアウェイトを前に
つけますこのうちにアウェイトをつけると
フルーチンが実行されてその処理が終わる
までここで待つことができます
処理の完了待ってるなら普通の築地処理と
同じじゃんって思うかもしれませんが
非同期処理では
処理の完了を待たずに別の処理もできるし
ある処理においては
完了待ってからさらに次の処理も進め
るっていう
柔軟なプログラムが作れます
なので一旦処理の完了を待って次の処理を
するっていうこの実装を動かしてみたいと
思いますそしてアウェートの部分で
ちゃんと待ってるかを確認するために
タイムモジュールをインポートしてメイン
の開始と終了のプリント文のところに現在
の時間を表示させようと思いますこれを
実行してみると
処理時間の
合計が3秒なのでアウェイトのところで
処理の完了を待ってるのがわかりますね
またコルーチンをアウェイトで呼び出して
いる部分を関数に切り出そうと思った時
その関数は青いと一時停止があるのでその
関数もコルチにする必要がありますどう
いうことかというと例えば1秒スリープ
するこの部分を別の関数にこんな風に
切り出したとします分かりやすいように
Awayとする前に
プリント分で何秒も使う表示させておき
ます今これは普通の関数のように切り出し
たのですがファンクション1はアウェイト
が存在するのでFの前にシンクをつけて
コルチにする必要がありますそしてこの
ファンクション1はコルーチンなのでこの
ままだとファンクション1は動きません
なので前にアウェイトをつけてコルーチン
が実行されるようにしますこれでスリープ
を含む処理をゴルーチンとして切り出す
ことができましたまた戻り値がある場合を
考えてみますリターンで返した値は
アウェイトの左側で通常と同じように
イコールを使って変数に代入することが
できます
リターンで何秒の待機に成功しましたって
文字列を書いてメイン側で受け取って表示
をするという行動をかけました実際にこれ
を実行してみると
先ほどと同じように処理に3秒かかって
処理の完了まで待っていることと戻り値が
メイン側で受け取れることがわかります
では次にコルーチンを平行処理で動かそう
と思いますごルーチンを平行処理で動かす
にはタスクというものを作る必要があり
ます
クリエイトタスクの中でコルチを呼び出す
とオルーチンをラップしたタスクが作られ
ますなので今回は1秒スリープする
コルーチンをラップしたタスク1と2秒
スリープするコルーチンをラップした
タスクに2つのタスクを作りました
アウェイトの右側にタスクを指定すること
でそのタスクが実行できますそしてタスク
は平行処理されるのでこのように書くと
タスク1とタスクには同時に処理が走り
ますこのコードを実行してみると
今度は2秒で処理が完了したのがわかり
ますつまりタスク1とタスク2が平行処理
されたことが分かりますねまたこのタスク
を使って戻り値を取得することもできます
例えば先ほどと同じファンクション1と
いうコルージンを作ってそのコルージン
からラスク1とタスクにを作ります
ウェイトでタスクを実行した後アメリカ
から抜けたところでそれぞれのタスクの
リターンを呼び出すと丸1を得ることが
できますこのコードを実行してみると
タスクが平行処理されてさらにメイン側で
戻り値を取得することができましたね次に
ギャザーというものを紹介しますこれは
複数のクルーチンやタスクを平行処理する
ことができてさらに平行処理で実行した
それぞれの戻り値をまとめて受け取ること
ができるものです書き方はアウェイトの
後ろで真空IOをギャザーを呼び出して
引数に平行を処理させたいタスクや
コルーチンを指定すればOKです
ブルーチンが指定された場合は内部で
タスクにラップされますまたこの動画では
紹介していませんがFutureっていう
ものを指定することもできます
フューチャーとは
非同期処理の最終結果を表すものですが
直接扱うことはほとんどないのでそんな
ものがあるのかくらいの認識で大丈夫です
こんな風にタスクもコルチも同時に引数に
指定できますそして戻り値をリサルツと
いう変数に代入してこれをプリント文で
表示してみようと思いますこれを実行する
と
ユーザーの引数に指定したタスクと
コルーチンが平行処理されて戻り値が
リストの要素としてリザルツに格納された
のがわかりますねここまでのコードは全て
コルチにあるエーシンクIOのスリープを
使っていましたでも普通の関数をどうして
も深海王で扱いたいなという時があるかも
しれませんそんな時は
LANinエグゼキューターというものを
使います
エグゼキューターを使って普通の関数で
あるタイムモジュールのスリープをシンク
アウェイトの非同期処理で扱えるようにし
てみます
ちなみにファンクション1のスリープを
タイムモジュールのスリープに変更して
これで動かすと
エラーになりますアウェイとタイム
スリープのところでエラーになってるのが
わかりますねアウェイトの後ろには普通の
関数が指定できないからですなのでまず
レーシングIOのGetランニングループ
お呼び出して現在スレッドで動いている
イベントループを取得しますで取得した
そのイベントループのラン
インエグゼキューターを呼び出します第一
引数にはエグゼキューターを指定して第2
引数には対象の関数を指定して第3引数に
対象の関数に渡す引数を指定します第1
引数に指定するエグゼキューターは
並列処理の動画で解説したスレッドプール
エグゼキューターやプロセスプール
エグゼキューターを指定できますが特に
指定がない場合は何にしておきますこの
場合デフォルトのエグゼキューターが使わ
れますこれでOKですもう一度この
スクリプトを動かしてみると
タイムモジュールのスリーブが
並行処理されたのがわかりますねあとは
タイムアウトで処理をキャンセルさせる
こともできます例えばこの処理時間が
かかると言っても10分経っても終わら
ないならもうそれは途中で止めちゃいたい
なーっていうことってありますよねその
場合は
thinkIOの
ウェイト4を使って指定したタイムアウト
時間を過ぎたら例外を投げるようにします
トライの中でアウェイトの後ろに
レーシングIOの
ウェイト4を指定して内地引数に実行し
たいコルジンを指定しタイムアウトの引数
に何秒でタイムアウトさせるかを指定し
ます
今回は
完了に10秒かかるコルーチンを指定して
タイムアウトを3秒にしてみますもしも
タイムアウトせずに処理が終わった時は
ファンクション1の戻り値を表示させる
ようにしておきますそしてタイムアウトし
た場合はエイシンク
IOをタイムアウトエラーという例外が
発生するので
xyptで例外を指定してタイムアウトを
取って表示するようにしてみましたこれを
実行してみると
確かに3秒で処理が終わって戻り値が表示
されずにタイムアウトしたのがわかります
ね
ここまでの構文解説ではコードが読み
やすいようにスリープを使っていたんです
がいまいち実際にエーシンクアウェイトを
使うコードのイメージがしにくいかなと
思ったので最後に実際のファイル
ダウンロードで
非同期処理を動かしてみようと思います
ファイルのダウンロードですが今回は
AzureというMicrosoftの
クラウドサービスのファイル共有サービス
からファイルをダウンロードする処理を
行うと思いますAzureのPython
用のsdkはファイルのアップロードや
ダウンロードの処理に
非同期のものとそうでないもの両方が用意
されています今回は
非同期処理のものを使うと思いますまた
AzureのPython用sdkの
詳しい使い方は本題とはそれるので割愛し
ますただコードの中のダウンロードの部分
は今まで解説してきたシンクIOの
スリーブと同じなのであウェイトで
呼び出せるんだなこれはコルチーノだなっ
ていう理解で大丈夫です
そして今こんな風に3つのファイルが
クラウド上にありますこのファイルを
シンクアウェイとでダウンロードしたいと
思いますまず先ほどと同じように深くIO
とタイムをインポートしておいて
Azureのファイル共有に接続するため
のコネクション文字列もインポートして
おきますあとはAzureのファイル共有
用のクライアントモジュールもインポート
しておきますそしてダウン
ロードっていう関数を作ってシンクをデフ
の前につけてコルチにしますこの中に
先ほどのAzureのドキュメントに書い
てあった通りにファイルダウンロードの
コードを書いていきます今追加した部分は
ファイル名とパスの指定以外は
ドキュメントのコードと全く同じです
そしてファイルクライアントのクローズを
しますこれも黒字なのでハワイプをつけて
くださいダウンロード対象のファイル名は
引数ファイルで受け取るようにしました
あとは開始のタイミングと終了ので
プリント文を使って時間を出力させておき
ますそしてメイン関数のAシンクをつけて
くるうちにしてこの中でasyncIOの
ギャザーを使って3つのファイルの
ダウンロードを呼び出しますこれを実行し
たいのですがここでWindowsの人
だけに注意がありますどうやら使っている
ライブラリーのバグによってこのような
コードを入れる必要があります
プラットフォームのシステムが
Windowsの時にエーシンクIOの
Setイベント
ループポリシーを呼び出して
引数に
英進会をWindowsセレクター
イベントループポリシーを指定して
ください
これを実行してみると
3つのファイルのダウンロードが一斉に
始まったのがわかりますねおそらく一番
ファイルサイズの小さいビッグファイル3
っていうファイルからダウンロードが完了
すると思います
これで全部終わったみたいですねこんな風
に
非同期対応のライブラリを扱う必要がある
時でもこの動画で紹介したエーシンク
アウェイトの扱い方がわかれば適切に扱う
ことができますね
今回の動画は以上になりますそれではまた
次回の動画でお会いしましょうバイバイ
[音楽]
تصفح المزيد من مقاطع الفيديو ذات الصلة
【Pythonプログラミング】並列処理の基本を解説!マルチスレッド・マルチプロセスをconcurrent futuresで実装!
Introduction to Query Pipelines (Building Advanced RAG, Part 1)
How To Make ANY Function Asynchronous In Python 3.12
【Python入門 #5】リストと繰り返し | ループ処理をマスター
The Node.js Event Loop: Not So Single Threaded
Writing a Physics Engine from scratch - collision detection optimization
5.0 / 5 (0 votes)