PythonでFuture・Taskを使う(asyncio, Python 3.5以降)
この記事では、Python 3.5以降で導入された`asyncio`における`Future`と`Task`の使い方を解説します。非同期プログラミングにおいて、これらのオブジェクトがどのように役立つのか、具体的な例を通して理解を深めます。
目次
Futureオブジェクト
`Future`は、非同期操作の結果を保持するオブジェクトです。`asyncio.Future`を使用して作成し、`result()`メソッドで結果を取得します。`done()`メソッドで操作が完了したかどうかを確認できます。
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
return 'Hello from coroutine!'
async def main():
future = asyncio.Future()
asyncio.create_task(my_coroutine()).add_done_callback(lambda f: future.set_result(f.result()))
result = await future
print(result)
await main()
上記の例では、`my_coroutine`を`Task`として実行し、その結果を`Future`オブジェクトに設定しています。`await future`で`Future`が完了するまで待ち、結果を取得します。
Taskオブジェクト
`Task`は、`asyncio.create_task()`で`coroutine`を実行して作成されます。`Future`オブジェクトと似ていますが、`coroutine`の実行を管理する役割を担います。`Task`オブジェクト自体も`Future`を継承しているため、`result()`や`done()`メソッドも使用できます。
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
return 'Hello from coroutine!'
async def main():
task = asyncio.create_task(my_coroutine())
result = await task
print(result)
await main()
この例では、`create_task()`で`my_coroutine`を実行し、`Task`オブジェクトを取得。`await task`で完了を待って結果を取得しています。
FutureとTaskの違い
簡単に言うと、`Future`は非同期操作の結果を表すオブジェクト、`Task`は`Future`を管理し、`coroutine`の実行を制御するオブジェクトです。`Task`は`Future`のサブクラスであり、`Future`の機能をすべて継承しています。通常、`asyncio.create_task()`を使用して`Task`を作成し、直接`Future`を作成する必要はほとんどありません。
- `Future`は結果を保持する
- `Task`は`coroutine`の実行を管理する
- `Task`は`Future`のサブクラス
実践例:複数の非同期操作を同時に行う
複数の非同期操作を同時に行うには、複数の`Task`を作成し、`asyncio.gather()`を使って結果を待ちます。
import asyncio
async def fetch_data(url):
await asyncio.sleep(1) # シミュレーション
return f'Data from {url}'
async def main():
urls = ['url1', 'url2', 'url3']
tasks = [asyncio.create_task(fetch_data(url)) for url in urls]
results = await asyncio.gather(*tasks)
print(results)
await main()
この例では、3つのURLからデータを取得する非同期操作を同時に実行し、`asyncio.gather()`で結果をリストとして取得しています。
エラーハンドリング
`Task`または`Future`が例外を発生させた場合、`result()`メソッドは例外を再発生させます。`try...except`ブロックで例外をキャッチすることができます。
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
raise Exception('Something went wrong!')
async def main():
task = asyncio.create_task(my_coroutine())
try:
result = await task
print(result)
except Exception as e:
print(f'An error occurred: {e}')
await main()
この例では、`my_coroutine`が例外を発生させますが、`try...except`ブロックで適切に処理されています。
関連記事
- Pythonで非同期処理を使う(asyncio, Python 3.5以降)
- Pythonでコルーチンを使う(asyncio, Python 3.5以降)
- Pythonで非同期関数を定義する(async def, Python 3.5以降)
- Pythonでスレッドプール・プロセスプールを使う(concurrent.futures)
- Pythonでスレッドを使う(threading)
- Pythonでプロセスを使う(multiprocessing)
- Pythonでスレッド間・プロセス間通信
- Pythonでジェネレータ関数を使う(yield)
- Pythonでaiohttpを使って非同期HTTPリクエストを送信 (Python 3.5以降)
- Pythonでコールバック関数を使う