見出し画像

Pythonでマルチスレッド

実行したいこと複数ある場合の実行方法について考えます。通常は命令の順番通りに実行していきます。複数実行したい場合でも一つ終わってから次の処理を行うことになります。この処理は同期処理と言います。

複数同時、割り込んで実行することを非同期処理と言います。この非同期処理ですが、複数の処理を完全に別に行うものと一つの処理の中で割り込みながら並行して行うものがあります。

複数同時に行う、別処理として行うことをマルチスレッドと呼ぶこともあります。

マルチスレッドの実現には"threading"を使用します。もう一つの非同期に処理ができる方法には"asyncio"を使用して実現します。


threading

Pythonでは、それをスレッドとして複数同時に取り扱うことが可能です。
このテクニックをマルチスレッドと呼びます。

"threading"を使わない方法。関数process()をそのまま書いて実行します。

import time

def process():
    print('Process Start')
    time.sleep(3)
    print('Process End')

print('Main Start')

process()

time.sleep(1)

print('Main End')

process()で3秒、の次にtime.sleep(1)を実行するので約4秒かかります。

・Main Start
・Process Start
・Process End
・Main End

という順番に実行されます。上から順番に実行しているので最後に"Main End"が出力されます。順番、同期的な処理となります。

次に"threading"を使う方法

import threading
import time

def process():
    print('Process Start')
    time.sleep(3)
    print('Process End')

print('Main Start')

threadA = threading.Thread(target=process)
threadA.start()

time.sleep(1)

threadA.join()

print('Main End')

・Main Start
・Process Start
・Main End
・Process End

この場合は"Process Start"で3秒待っている間に"time.sleep(1)"が実行されるので全体では約3秒で終了します。最後の処理も"Process End"となっていて、3秒終了と同時に出力(非同期、並列に処理)されていることがわかります。

asyncio


asyncio は async/await 構文を使い 並行処理の コードを書くためのライブラリです。

公式のドキュメントにもあるコードを実行します。

import asyncio

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

asyncio.run(main())

まず、VSCodeのjupyterの実行しようとするとエラーが出ます。調べて見ると

Jupyter自身のイベントループ上で新たにイベントループを開始しようとしたために起こったエラー。非同期処理を実行させたければ、await関数で直接実行させれば良い。

import asyncio
import datetime

async def display_date():
    """現在時刻を5秒間表示する"""
    loop = asyncio.get_running_loop()
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if(loop.time()+1.0)>=end_time:
            break
        await asyncio.sleep(1)

x : asyncio.run(display_date())
○ : await display_date()

ということらしいので

import asyncio

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

await  main()

として実行するとうまくいきます。

以下のサイトでいろんなasyncioが紹介されています。

その中でうまく非同期処理されているものは

import asyncio

async def func1():
    print('func1() started')
    await asyncio.sleep(1)
    print('func1() finished')

async def func2():
    print('func2() started')
    await asyncio.sleep(1)
    print('func2() finished')

async def main():
    task1 = asyncio.create_task(func1())
    task2 = asyncio.create_task(func2())
    await task1
    await task2

await  main()

実行すると、

func1() started
func2() started
func1() finished
func2() finished

と出力されます。非同期処理されほぼ同時に終わっています。うまくいっています。

うまくいかない場合、

import asyncio
import time

async def func1():
    print('Process Star')
    await asyncio.sleep(3)
    print('Process End')

async def main():

    print('Main Start')
    task1 = asyncio.create_task(func1())
    await task1
  
    time.sleep(1)

    print('Main End')

await  main()

とすると、

Main Start
Process Star
Process End
Main End

asyncioで非同期の処理が終わってから"time.sleep(1)"が実行されてしまいます。これでは非同期処理としてはうまくいきません。

このことからasyncioは基本的にはシングルスレッドなのがわかります。


この記事が気に入ったらサポートをしてみませんか?