【Python】aiofilesを用いた非同期ファイル入出力

Pythonで、aiofiles を用いて非同期にファイル入出力する方法を解説します。
aiofiles による非同期ファイル入出力
非同期処理とは、複数のタスクを協調的に実行するプログラミング手法です。特に I/O バウンドな処理において有効であり、Python でも非同期プログラミングの仕組みが整備されてきました。
async / await は Python 3.5 で導入されましたが、当初はイベントループを明示的に管理する必要がありました。現在は Python 3.7 以降で asyncio.run() が導入されることでイベントループの生成や終了処理が自動化され、より簡潔に非同期処理を書けるようになっています。
この記事では、非同期処理での効果が期待できるファイル入出力に焦点を当て、aiofiles を用いて非同期にファイル入出力する方法を紹介します。
aiofiles とは
aiofiles は、Python の非同期 I/O 操作を扱うためのライブラリです。Pythonの asyncio モジュールを使って非同期プログラミングを行う際に、ファイル操作を非同期で操作する場合に使用できます。
非同期プログラミングは、I/O バウンドな処理の実装には非常に有益な方法です。I/O バウンドな処理とは、ファイルへの入出力やネットワーク通信等が該当します。
通常、ファイル入出力はブロッキング操作となり、大きなファイルを扱うときにプログラムの実行が停止してしまう可能性があります。aiofiles を使用すると、これらの操作を非同期に実行でき、プログラムの他の部分がファイル操作の完了を待つ間に動作を継続することができます。
aiofiles を用いた非同期ファイル入出力の基本
aiofiles を使って非同期にファイル入出力する方法を紹介します。
aiofiles のインストール
aiofiles はサードパーティ製ライブラリのため、インストールをしてください。
pip install aiofiles
uv を使用している場合は、以下でインストールしてください。uv は高速な Python パッケージ管理ツールであり、pip の代替として利用できます。
uv add aiofiles
aiofiles の基本的な使い方
aiofiles は、標準モジュールの read や write 等の非同期版として提供されているため引数などは標準入出力モジュールと同じような使い方になります。標準ファイル入出力については「ファイル入出力の基本」を参考にしてください。
標準のファイル入出力との主な違いとしては、関数定義に async def を用いることや関数実行時に await キーワードを使用することです。また、async with を使うことでファイルの資源管理を適切に行います。
ファイルの非同期書き込み
aiofiles を使って非同期にファイルを書き込むには以下のようにします。
import asyncio
import aiofiles
async def write_file(filename, content):
"""非同期ファイル書き込み関数"""
async with aiofiles.open(filename, "w", encoding="utf-8") as file:
await file.write(content)
async def main():
# 書込み内容の準備
files_and_contents = {
"sample1.txt": "サンプルファイル1",
"sample2.txt": "サンプルファイル2",
"sample3.txt": "サンプルファイル3",
"sample4.txt": "サンプルファイル4",
"sample5.txt": "サンプルファイル5",
}
# 書き込みタスクを作成
task = [
write_file(filename, content)
for filename, content in files_and_contents.items()
]
# 非同期に複数ファイルを書き込む
await asyncio.gather(*task)
if __name__ == "__main__":
# asyncio.runを使用してメインコルーチンを実行
asyncio.run(main())非同期のファイル入出力では、asyncio と aiofiles をインポートして使用します。上記のプログラムでは、複数のテキストファイルに非同期に書き込みを行っています。
処理の中心は write_file という非同期関数です。この関数は、指定されたファイル名(filename)で新しいファイルを開き、指定した内容(content)を非同期に書き込みを行います。
非同期にファイルを開く場合には、aiofiles.open を async with で使用し、書き込み時の write では、await キーワードを指定することで非同期に書き込み操作を行います。これにより I/O 待ち時間を効率的に利用することができます。
メインコルーチン(main)では、書き込むファイル名と内容を files_and_contents で管理して非同期のタスクを作成します。これらのタスクは asyncio.gather を使って非同期に実行され、すべてのファイル書き込みが完了するまで待機します。
上記のようにすることで非同期にファイルの書き込みを行うことが可能です。
ファイルの非同期読み込み
aiofiles を使って非同期にファイルを読み込むには以下のようにします。なお、上記で紹介したプログラムを実行するなどして sample1.txt 等のファイルが既に存在することを前提とします。
import asyncio
import aiofiles
async def read_file(filename):
"""非同期ファイル読み込み関数"""
async with aiofiles.open(filename, "r", encoding="utf-8") as file:
content = await file.read()
return content
async def main():
# 読み込みファイルリスト
files = [
"sample1.txt",
"sample2.txt",
"sample3.txt",
"sample4.txt",
"sample5.txt",
]
# 読み込みタスクを作成
task = [read_file(filename) for filename in files]
# 非同期にファイルを読み込む
results = await asyncio.gather(*task)
print(results)
if __name__ == "__main__":
# asyncio.runを使用してメインコルーチンを実行
asyncio.run(main())【実行結果】 ['サンプルファイル1', 'サンプルファイル2', 'サンプルファイル3', 'サンプルファイル4', 'サンプルファイル5']
上記のプログラムでは、複数のテキストファイルを非同期に読み込みます。
処理の中心は read_file という非同期関数です。この関数は、指定されたファイル名(filename)で新しいファイルを開き、読み込んだ内容を返却します。
メインコルーチン(main)では、読み込むファイル名をリストで管理し、非同期の読み込みタスクを作成します。これらのタスクは asyncio.gather を使って非同期に実行され、すべてのファイルの読み込みが完了すると、結果が results に格納されます。結果表示を見てもファイルの内容が読み込めていることが分かります。
上記のようにすることで非同期にファイルを読み込むことが可能です。
まとめ
Pythonで、aiofiles を用いて非同期にファイル入出力する方法を解説しました。
aiofiles は、Python の非同期 I/O 操作を扱うためのライブラリで、非同期プログラミングを行う際に、ファイル操作を非同期で操作する場合に使用できます。今回は、簡単な非同期入出力の例を用いて基本的な使い方を紹介しました。
非同期プログラミングは、I/O バウンドな処理を実装するためには非常に有益な実装方法です。ファイルアクセスについても適切に使用することができれば、性能を向上できる可能性があります。ぜひ、aiofiles について使い方の基本を理解していただき、非同期処理をしてみてもらいたいと思います。

