がくしです。
前回同様、APIを使ったプログラミングの実行速度を上げる手法を紹介します。今回は非同期処理を使います。まずはじめに非同期処理の解説をして、最後にAPIへの応用をお見せします。
複数のタスクを実行する際に、あるタスクの処理が停止している間に別のタスクの処理を進める手法です。各タスクは、coroutineという形式で管理されます。
この説明だけでは分からないと思うので、coroutineについて説明していきます。ポイントは3つあります。
・coroutineの作り方/使い方
・coroiutineの連鎖
・coroutineの並列
それぞれ見てみましょう。
async
関数定義の頭にasyncを書くことで、その関数をcoroutineとすることができます(正確には、関数の実行結果がcoroutineです)。ここでは、parent関数とchild関数をcoroutineとして定義しています。
loop
この3行でcoroutineを実行できるとだけ理解してもらえれば十分です。
複数のcoroutineは、awaitを通じて連鎖させることができます。もう一度コードを見てみましょう。
parentでは「await child(num)」という形で使われています。これは、「child(num)のタスクが完了するまで待ってから以降の処理を行う」という意味になります。これがcroutineの連鎖です。
childでは「await async.sleep(num)」という形で使われています。async.sleep(num)は、「num秒待機する」というタスクを課したcoroutineを返します。
実行結果は以下のようになります。childの完了後に、await以降の処理が行われている事がわかります。
$ python simple_coroutine.py
Bob start
Bob's child waiting...
Bob's child waited 3sec
Bob end
coroutineは並列することでその真価を発揮します。もう一度、最初の説明を見てみましょう。
複数のタスクを実行する際に、あるタスクの処理が停止している間に別のタスクの処理を進める手法
これは、「coroutineを並列して実行している際に、あるcoroutineがawaitしている間に別のcoroutineの処理を進める」という意味になります。実際のコードを見てみましょう。新しくparallelという関数を追加しました。
新しくparallelという関数を追加しました。BobとAliceという2つのcoroutineを作成し、並列処理をしています。async.waitが、並列処理を管理するcoroutineとなります。実行結果を見てみましょう。
$ python parallel_coroutine.py
Alice start
Alice's child waiting...
Bob start
Bob'child waiting...
Bob's child waited 3sec
Bob end
Alice's child waited 5sec
Alice end
Aliceが開始しAlice's childが待機している間に、Bobが動いている事が分かります。これが、非同期処理です。
・タスクをcoroutineの形式で管理
・awaitでcoroutineを連鎖
・await中に別のcoroutineを処理
これらを踏まえて、APIへの応用を見てみましょう。
aiohttp
urlopenやrequestは非同期処理に対応していないので、aiohttpを使用。
asyncio.Queue()
非同期処理の出力を管理
前回と同様に、1000件の記事のlike数を取得するのに要する時間を測定しています。
・シングルスレッド(通常の処理)
・マルチスレッド(前回作ったもの)
・非同期処理(今回作ったもの)
通常の処理が2分程かかるのに対して、非同期処理だと5秒ほどで済むことが分かります。25倍以上の速度改善がなされてます。爆速ですね。
今回は解説にも挑んでみましたが、やはり難しいものですね。ただ、コード自体は小奇麗にまとまってると思うので、せめてそこだけでも誰かのお役に立てれば幸いです。
かしこ。