[Python] 병렬 동시 처리 메모

16132 단어 파이썬Python3

참고한 기사



구체적인 예에서 이해하고 싶을 때 읽기
파이썬 병렬 및 병렬 처리 샘플 코드 요약

어떤 때 사용하는지 고민했을 때 읽기
Python의 비동기 처리 : asyncio 역방향 참조

이론을 배우다



Python에는 threading, multiprocessing, asyncio와 모두 병렬 처리에 사용할 수 있는 패키지가 3개 있습니다. 이러한 차이를 먼저 누른다.

이러한 패키지의 차이는 그대로 "멀티 스레드", "멀티 프로세스", "논 블로킹"의 차이에 해당합니다. 첫째, 멀티 스레드와 멀티 프로세스의 차이점에 대해.

프로세스 풀



스레드가 아닌 프로세스 단위로 나누면 Global Interpreter Lock(GIL)의 제약을 받지 않게 되어 멀티 코어로 움직일 수 있게 됩니다.
그러나 그만큼 스레드보다 규모가 큰 프로세스를 사용하기 때문에 다른 제약이 늘어날 수도 있습니다. 주의!
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=4)

    for i in range(10):
        if i % 2 == 0:
            executor.submit(func1)
        else:
            executor.submit(func2)
    print('loop end')


작업자를 4로 하면 4개 이상 프로세스가 기동하지 않는 것을 알 수 있다
func1
func2
func1
func2
loop end
func1
func2
.
.
.

여러 프로세스에 여러 스레드를 구축



멀티 태스킹을 실현하는 데 도움이되는 관계 다이어그램

출처 : h tps : // s ぃ에서 sp ぁ ぇ r. 네 t/sぃ로/11222023/
"""
プロセス1にスレッド2つ起動
プロセス2にスレッド2つ起動

目標
① 同じプロセスにあるスレッド間のデータ共有 (スレッド間通信)
② 異なるプロセス間のデータ共有 (プロセス間通信)

"""
import time
import threading
from multiprocessing import Process, Value
from functools import partial

class PS():
    # def __init__(self,ps_name,sl2,shm):
    def __init__(self,ps_name,sl2):
        self.ps_name=ps_name
        self.sl2=sl2
        self.is_quitting=False # ① スレッド間通信
        # self.shm=shm           # ② プロセス間通信
        self.th1=threading.Thread(target=self.fn1)
        self.th2=threading.Thread(target=self.fn2)

        # 各スレッドの起動
        print(f'{self.ps_name}: 1つ目のスレッド 起動')
        self.th1.start()
        print(f'{self.ps_name}: 2つ目のスレッド 起動')
        self.th2.start()
        print(f'現在起動中のスレッド: {threading.active_count()}')

        # 各スレッドの終了を待つ
        self.th1.join()
        print(f'{self.ps_name}: 1つ目のスレッド 停止')
        self.th2.join()
        print(f'{self.ps_name}: 2つ目のスレッド 停止')
        print(f'現在起動中のスレッド: {threading.active_count()}')

        # このプロセスが終了したことを他のプロセスへ知らせる
        # self.shm.value=1  # ② プロセス間通信
        shm.value=1  # ② プロセス間通信

    def fn1(self):
        """
        終了フラグが立つまで1秒間隔で標準出力する
        """
        time.sleep(1)
        while not self.is_quitting:  # ① スレッド間通信
            print(f'{self.ps_name}: fn1: 実行中')
            # if self.shm.value:
            if shm.value:
                print(f'{self.ps_name}: どこかのプロセスが終了している') # ② プロセス間通信
            time.sleep(1)

    def fn2(self):
        """
        スレッド2が起動して数秒後にスレッド1を終了させるためのフラグを立てる
        """
        time.sleep(self.sl2)
        print(f'{self.ps_name}: fn2: 実行中')
        self.is_quitting=True # ① スレッド間通信
        print(f'\n{self.ps_name}: {self.ps_name}のfn1を終了します\n')


# 標準出力でプロセスを識別するために使う
name_ps1='プロセス1'
name_ps2='プロセス2'

# 共有メモリ(shared memory)
"""
メインスレッドで作成された共有メモリは、共有されるオブジェクトとなるので、引数で渡したり返却値に指定したりは不要
"""
shm = Value('i', 0) # 第一引数のiはc言語のint型を表す (詳しくはctypesで検索)

# プロセス1
# process1 = Process(target=PS, args=(name_ps1,2,shm)) # プロセス起動後2秒後にプロセス終了
process1 = Process(target=PS, args=(name_ps1,2)) # プロセス起動後2秒後にプロセス終了


# プロセス2
# process2 = Process(target=PS, args=(name_ps2,7,shm)) # プロセス起動後5秒後にプロセス終了
process2 = Process(target=PS, args=(name_ps2,7)) # プロセス起動後5秒後にプロセス終了

print(f'{name_ps1}: start')
process1.start()
print(f'{name_ps2}: start')
process2.start()

process1.join()
print(f'\n{name_ps1}: end\n')
process2.join()
print(f'\n{name_ps2}: end\n')

プロセス1: start
プロセス2: start
プロセス1: 1つ目のスレッド 起動
プロセス1: 2つ目のスレッド 起動
プロセス2: 1つ目のスレッド 起動
プロセス2: 2つ目のスレッド 起動
プロセス1: fn1: 実行中
プロセス2: fn1: 実行中
プロセス1: fn1: 実行中
プロセス1: fn2: 実行中

プロセス1: プロセス1のfn1を終了します

プロセス2: fn1: 実行中
プロセス1: 1つ目のスレッド 停止
プロセス1: 2つ目のスレッド 停止
プロセス2: fn1: 実行中
プロセス2: どこかのプロセスが終了している

プロセス1: end

プロセス2: fn1: 実行中
プロセス2: どこかのプロセスが終了している
プロセス2: fn1: 実行中
プロセス2: どこかのプロセスが終了している
プロセス2: fn1: 実行中
プロセス2: どこかのプロセスが終了している
プロセス2: fn2: 実行中

プロセス2: プロセス2のfn1を終了します

プロセス2: 1つ目のスレッド 停止
プロセス2: 2つ目のスレッド 停止

プロセス2: end

좋은 웹페이지 즐겨찾기