Pythonでasyncioを用いたセマフォアとロックの処理方法

この記事では、Pythonの非同期プログラミングライブラリ`asyncio`を用いてセマフォア(Semaphore)とロック(Lock)の処理方法について詳しく解説します。具体的なコード例とその解説、応用例を含めています。

目次

非同期プログラミングとは?

非同期プログラミングとは、単一のプログラム内で複数のタスクを効率よく並行して実行する方法です。Pythonでの非同期プログラミングには、`asyncio`というライブラリが広く使われています。

セマフォア(Semaphore)とは?

セマフォアは、同時にアクセスできるリソースの数を制限する仕組みです。`asyncio`でのセマフォアは、特に非同期処理において複数のコルーチンがリソースに同時アクセスするのを制御するために使用されます。

基本的なセマフォアの使用方法

Pythonの`asyncio`ライブラリでのセマフォアは、`asyncio.Semaphore`クラスを用います。

import asyncio

async def worker(sem):
    async with sem:
        print("Task acquired.")
        await asyncio.sleep(1)
        print("Task released.")

async def main():
    sem = asyncio.Semaphore(3)
    tasks = [worker(sem) for _ in range(5)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    asyncio.run(main())

この例では、セマフォアの上限を3に設定しています。したがって、一度に3つの`worker`コルーチンだけがセマフォアを取得できます。

ロック(Lock)とは?

ロックは、リソースに対する排他的なアクセスを提供する手法です。`asyncio`でのロックも、`asyncio.Lock`クラスを用いて非同期に排他制御を行います。

基本的なロックの使用方法

以下は、`asyncio`を用いたロックの基本的な使用方法です。

import asyncio

async def worker(lock):
    async with lock:
        print("Task acquired.")
        await asyncio.sleep(1)
        print("Task released.")

async def main():
    lock = asyncio.Lock()
    tasks = [worker(lock) for _ in range(5)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    asyncio.run(main())

この例では、一度に1つの`worker`コルーチンだけがロックを取得できます。

応用例1:複数のリソースへのアクセス制御

セマフォアとロックを組み合わせて、複数のリソースへのアクセスを制御する例です。

import asyncio

async def worker(sem, lock):
    async with sem:
        async with lock:
            print("Task acquired.")
            await asyncio.sleep(1)
            print("Task released.")

async def main():
    sem = asyncio.Semaphore(3)
    lock = asyncio.Lock()
    tasks = [worker(sem, lock) for _ in range(5)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    asyncio.run(main())

応用例2:タイムアウト付きロック

ロック取得時にタイムアウトを設定する例です。

import asyncio

async def worker(lock):
    try:
        async with asyncio.wait_for(lock.acquire(), timeout=1):
            print("Task acquired.")
            await asyncio.sleep(3)
            print("Task released.")
    except asyncio.TimeoutError:
        print("Timeout.")

async def main():
    lock = asyncio.Lock()
    tasks = [worker(lock) for _ in range(3)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    asyncio.run(main())

この例では、ロックの取得が1秒以内に行われない場合、`Timeout`と出力されます。

まとめ

この記事では、Pythonの`asyncio`ライブラリを使用してセマフォアとロックの処理方法について解説しました。これらの機能は非同期プログラミングで頻繁に使用されるため、理解しておくと非常に便利です。

コメント

コメントする

目次