aiofilesとasyncioを使用したPythonの非同期ファイル処理
読む所要時間: 8 分
非同期コードは、今ではPython開発の主力となっています。asyncioが標準ライブラリーに加わり、互換性のある機能がサードパーティーのパッケージで数多く提供される今、このパラダイムは今後も続くと考えられます。
非同期コードを作成する上で重要な点は、コードのすべてのパーツを上手く連携させることです。ある特定の要素が、他のすべての要素を遅延させる事態とならないよう、上手に連携させましょう。ファイルI/Oは、非同期処理連携においてよくある阻害要因です。そこで、この記事では、aiofilesライブラリーを使用してファイルを非同期処理する方法を説明します。
基本から始めましょう。、ファイルの内容を非同期で読み取るために必要なコードは以下になります。(非同期関数の中にあるものとします。)
では、詳しく見ていきます。
ノンブロッキングコードとは?
「非同期」、「ノンブロッキング」、「同時(並行)」はそれぞれよく聞く表現ですが、それぞれの意味は少しまぎらわしいところがあります。こちらのより詳細なチュートリアルによると、主な特性は次の2つです。
- 非同期ルーチンでは、最終結果を待つ間「一時停止」し、その間に他のルーチンを実行できる。
- 非同期コードは、上記メカニズムを通じ同時実行を促す。別の言い方をすると、非同期コードは同時実行の操作感を提供する。
このように非同期コードとは、結果待機中に他のコードを実行できるよう、自身の処理を一時停止することができるコードです。他のコードの実行を「ブロック」しないため、「ノンブロッキング」コードと言えます。
asyncioライブラリーには、Python開発者が非同期の処理を行うための、さまざまなツールがあります。またaiofilesには、ファイル操作専用の機能があります。
セットアップ
Python環境をあらかじめセットアップしておきます。必要に応じて、このガイドのvirtualenv(仮想環境)に関するセクションを参照してください。すべてが正常に動作するようにします。特に、仮想環境は、同じマシン上で複数のプロジェクトを実行している場合、dependency設定を分けるうえで重要です。この投稿で示すコードを実行するには、Pythonのバージョンは3.7以上であることが必要です。
環境のセットアップ後に、サードパーティーのライブラリーをいくつかインストールする必要があります。ここではaiohttpを使用します。仮想環境をアクティブにした後、次のコマンドでインストールしてください。
以降の例で利用するPokemon APIは、初代150ポケモンのデータをJSONファイルで保有しています。こちらから、すべてのファイルを格納したフォルダーをダウンロードできます。これで準備が整いました。次のステップに進んでコードを記述しましょう。
aiofilesによるファイル読み取り
まず、特定のポケモンに対応するファイルを開き、JSONファイルを解析して辞書に入れ、名前を出力しましょう。
このコードを実行すると、ターミナルに「articuno」と出力されます。ファイルを1行ずつ、非同期に反復処理することもできます。(その場合は、articuno.json
の全9271行が出力されます)
aiofilesによるファイル書き込み
ファイルの書き込みも、標準のPythonファイルI/Oと同様です。例えば、各ポケモン達が獲得できるすべての技をリストしたファイルを作成するとしましょう。簡単な例として、「transform(変身)」という技のみを取得できるポケモン Ditt(メタモン)の場合、情報を書き込むコードは以下となります。
同様に、次のポケモンRhydon(サイドン)の例を試してみましょう。サイドンは複数の技を持つため、コードは次のようになります。
上記のコードを実行した後、rhydon_moves.txt
を開いてみましょう。、以下のように112行分のファイル一覧を確認できるはずです。
asyncioを使用した複数ファイルの非同期処理
次はもう少し複雑になります。JSONファイルにある150ポケモンすべてを処理します。すべてのファイルを読み取り、解析してそれぞれのポケモンが持つ技を、新しいファイルに書き込みます。
このコードを実行すると、ポケモンファイルのディレクトリに.txt
ファイルと.json
ファイルが出力されます。ファイルには、それぞれのポケモンに対応する技リストが格納されています。
例えば、ファイル書き込み後に全ポケモンの技を一覧したいときなど、つまり、いくつかの非同期処理を実行させ、かつそれらの非同期処理を経た後のデータを取得したい場合、asyncio.ensure_future
とasyncio.gather
が使用できます。
各ファイルを処理するコード部分を、独自の非同期関数に分割し、それぞれの関数呼び出しに対し、Promiseを追加します。こちらがその関数の例です。このコードには新しいmain
関数が含まれています。
以上、HTTPリクエストの作成などに使用される、一般的なPythonの非同期コードの使用方法を紹介しました。
どこで利用する?
ポケモンデータを使用した今回の例では、aiofilesモジュールの機能と、ディレクトリ操作とファイルの読み込み/書き込みを行う方法を紹介しました。ファイルI/Oが非同期コード実装のブロッカーとならないコード作成のために、今回紹介したコードをぜひご活用ください。今回、aiohttpとasyncioを使用して何ができるかについてごく初歩的な説明をしました。これを手始めに、非同期Pythonの世界を少しでも身近に感じていただけるようになれば幸いです。
皆さんが何を構築されるか、とても楽しみです。体験談の共有やご質問など、どうぞお気軽にお問い合わせください。
- Email: sagnew@twilio.com
- Twitter: @Sagnewshreds
- Github: Sagnew
- Twitch (streaming live code): Sagnewshreds