LoginSignup
532

More than 5 years have passed since last update.

Pythonの並列・並行処理サンプルコードまとめ

Last updated at Posted at 2017-07-29

Pythonで同時に2つ以上の処理をする方法を紹介します

  • スレッド
  • スレッドプール
  • プロセスプール
  • イベントループ(コルーチン)

スレッド (threading)

スレッドを使えば、複数の関数を同時に動かすことができます。
threading.Thread クラスに target として関数を渡し、start() で開始すると動きます。

import time
import threading


def func1():
    while True:
        print("func1")
        time.sleep(1)


def func2():
    while True:
        print("func2")
        time.sleep(1)


if __name__ == "__main__":
    thread_1 = threading.Thread(target=func1)
    thread_2 = threading.Thread(target=func2)

    thread_1.start()
    thread_2.start()

実行結果

func1
func2
func2
func1
func1
func2
func2
func1

スレッドプール (concurrent.futures)

Python 3.2以降の、concurrent.futures パッケージ を使うとさらに強力です。
その中の ThreadPoolExecutor クラス を使います。

最初に同時に動かす最大数 max_workers を決めるとスレッドを使いまわしてくれるので上で紹介した普通のスレッドよりかしこいです。
Pythonのバージョンが新しいならば、積極的に使っていいと思います。

import time
import concurrent.futures


def func1():
    while True:
        print("func1")
        time.sleep(1)


def func2():
    while True:
        print("func2")
        time.sleep(1)


if __name__ == "__main__":
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
    executor.submit(func1)
    executor.submit(func2)

実行結果

func1
func2
func1
func2
func1
func2
func1
func2

プロセスプール (concurrent.futures)

上に同じく concurrent.futures パッケージ ですが、スレッドプールではなくプロセスプールというのもあります。

スレッドではなくプロセス単位に分けることで、Global Interpreter Lock (GIL) の制約を受けなくなりマルチコアで動かせるようになります。
ただし、その分スレッドよりも規模が大きいプロセスを使うので、他の制約が増えることも。注意!

使い方は簡単で、上で紹介した ThreadPoolExecutorProcessPoolExecutor に変えるだけです。

import time
import concurrent.futures


def func1():
    while True:
        print("func1")
        time.sleep(1)


def func2():
    while True:
        print("func2")
        time.sleep(1)


if __name__ == "__main__":
    executor = concurrent.futures.ProcessPoolExecutor(max_workers=2)
    executor.submit(func1)
    executor.submit(func2)

実行結果

func1
func2
func1
func2
func1
func2
func1
func2

イベントループ(コルーチン)

ひとつのスレッドで複数の処理を動かす方法もあります。そのひとつがイベントループです。
Python3.4以降では asyncio モジュール で実現できます。

マルチスレッドとの違い、どのような場合に使うと良いか…といったお話は Pythonにおける非同期処理: asyncio逆引きリファレンス を読むとわかりやすいです。

通信やファイル入出力といった非同期I/Oあたりにはスレッドを増やすよりも非常に効率的なのですが、概念が難しいのでなれるまで大変です・・。

サンプルコードはスレッドの場合とは結構違います。

待機する処理に time.sleep ではなく asyncio.sleep を使っていますが、これは asyncio.sleep を呼び出して待っている間に他の並列している処理に移動するためです。まさにコルーチンですね。

import asyncio


@asyncio.coroutine
def func1():
    while True:
        print("func1")
        yield from asyncio.sleep(1)


@asyncio.coroutine
def func2():
    while True:
        print("func2")
        yield from asyncio.sleep(1)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    tasks = asyncio.wait([func1(), func2()])
    loop.run_until_complete(tasks)

実行結果

func2
func1
func2
func1
func2
func1
func2
func1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
532