Pythonでの非同期処理: asyncioとマルチスレッド/プロセスの違いと使い分け

この記事では、Pythonでよく使用される非同期処理について詳しく説明します。特に`asyncio`とマルチスレッド/プロセスの違いと使い分けに焦点を当て、具体的なコード例とその解説、応用例を含めています。

目次

非同期処理とは?

非同期処理とは、一つのタスクが完了するのを待たずに次のタスクを開始する処理のことです。これにより、リソースを効率よく使用することができます。

同期処理との違い

同期処理は一つのタスクが完了するまで次のタスクが待機する処理方式です。対照的に、非同期処理では複数のタスクを並行して処理できるのが特徴です。

Pythonでの非同期処理手法

Pythonでの非同期処理には主に以下の3つの手法があります。

  • `asyncio`
  • マルチスレッド
  • マルチプロセス

asyncioとは

`asyncio`はPythonの標準ライブラリで、シングルスレッドの非同期I/Oをサポートします。

import asyncio

async def main():
    print("Hello")
    await asyncio.sleep(1)
    print("World")

asyncio.run(main())

上記のコードは、`Hello`と表示した後に1秒待ってから`World`と表示します。`await`は非同期処理を行うためのキーワードです。

マルチスレッドとは

マルチスレッドは、1つのプロセス内で複数のスレッドを生成して並行処理を行います。

import threading

def print_numbers():
    for i in range(10):
        print(i)

thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_numbers)

thread1.start()
thread2.start()

このコードは、二つのスレッドで`print_numbers`関数を並行に実行します。

マルチプロセスとは

マルチプロセスは、複数のプロセスを生成して並行処理を行います。これはCPU密集型のタスクに適しています。

from multiprocessing import Process

def print_numbers():
    for i in range(10):
        print(i)

process1 = Process(target=print_numbers)
process2 = Process(target=print_numbers)

process1.start()
process2.start()

使い分けのポイント

I/OバウンドとCPUバウンド

I/Oバウンド(ディスクやネットワークに依存する処理)の場合は、`asyncio`が適しています。CPUバウンド(計算処理が多い)の場合は、マルチプロセスが有効です。

コードの複雑性

`asyncio`はコードがシンプルになる傾向がありますが、マルチスレッド/プロセスは状態管理が複雑になる可能性があります。

応用例

Webスクレイピング

`selenium`と組み合わせて非同期にWebページを取得する場合は、`asyncio`が便利です。

from selenium import webdriver
import asyncio

async def fetch_page(url):
    driver = webdriver.Chrome()
    driver.get(url)
    content = driver.page_source
    driver.quit()
    return content

async def main():
    urls = ["https://example.com/page1", "https://example.com/page2"]
    tasks = [fetch_page(url) for url in urls]
    await asyncio.gather(*tasks)

asyncio.run(main())

画像処理

画像処理を行う場合、マルチプロセスを使用して高速化することが可能です。

from PIL import Image
from multiprocessing import Process

def process_image(image_path):
    img = Image.open(image_path)
    img = img.convert("L")
    img.save(f"processed_{image_path}")

if __name__ == '__main__':
    image_paths = ["image1.jpg", "image2.jpg"]
    processes = [Process(target=process_image, args=(image_path,)) for image_path in image_paths]
    for p in processes:
        p.start()

まとめ

非同期処理は効率的なプログラミングに必要な手法です。Pythonでは`asyncio`、マルチスレッド、マルチプロセスといった複数の非同期処理手法があります。使い分けにはI/Oバウンド性やCPUバウンド性、コードの複雑性が影響します。具体的な応用例として、Webスクレイピングや画像処理がありました。

コメント

コメントする

目次