source

파이썬 멀티스레드는 모든 스레드가 완료될 때까지 기다립니다.

manycodes 2023. 7. 15. 10:19
반응형

파이썬 멀티스레드는 모든 스레드가 완료될 때까지 기다립니다.

비슷한 맥락에서 물어본 것일 수도 있지만 20분 정도 검색해보니 답을 찾지 못해서 물어보겠습니다.

저는 파이썬 스크립트(예: scriptA.py )와 스크립트(예: B 스크립트)를 작성했습니다.파이)

스크립트 B에서 저는 다른 인수로 스크립트 A를 여러 번 호출하고 싶습니다. 매번 실행하는 데 약 한 시간이 걸립니다. (커다란 스크립트로 많은 일을 합니다.)걱정하지 마세요) 그리고 저는 스크립트 A를 모든 다른 인수와 동시에 실행할 수 있기를 원하지만, 계속하기 전에 모든 인수가 완료될 때까지 기다려야 합니다. 제 코드:

import subprocess

#setup
do_setup()

#run scriptA
subprocess.call(scriptA + argumentsA)
subprocess.call(scriptA + argumentsB)
subprocess.call(scriptA + argumentsC)

#finish
do_finish()

나는 모든 것을 실행하고 싶습니다.subprocess.call()동시에 모든 작업이 완료될 때까지 기다리십시오. 어떻게 해야 합니까?

여기 예시와 같이 스레드화를 사용하려고 했습니다.

from threading import Thread
import subprocess

def call_script(args)
    subprocess.call(args)

#run scriptA   
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()

하지만 저는 이것이 옳다고 생각하지 않습니다.

내가 어떻게 그들이 모두 달리기를 끝냈는지 알 수 있습니까?do_finish()?

스레드를 목록에 넣은 다음 가입 방법 사용

 threads = []

 t = Thread(...)
 threads.append(t)

 ...repeat as often as necessary...

 # Start all threads
 for x in threads:
     x.start()

 # Wait for all of them to finish
 for x in threads:
     x.join()

의 가입 방법을 사용해야 합니다.Thread개체입니다.

t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

따라서 주 스레드는 다음 시간까지 기다립니다.t1,t2그리고.t3집행을 마치다

Python3에서는 Python3.2 이후 동일한 결과에 도달하기 위한 새로운 접근 방식이 있습니다. 저는 개인적으로 전통적인 스레드 생성/시작/가입, 패키지보다 선호합니다.concurrent.futures: https://docs.python.org/3/library/concurrent.futures.html

사용ThreadPoolExecutor코드는 다음과 같습니다.

from concurrent.futures.thread import ThreadPoolExecutor
import time
    
def call_script(ordinal, arg):
    print('Thread', ordinal, 'argument:', arg)
    time.sleep(2)
    print('Thread', ordinal, 'Finished')
    
args = ['argumentsA', 'argumentsB', 'argumentsC']
    
with ThreadPoolExecutor(max_workers=2) as executor:
    ordinal = 1
    for arg in args:
        executor.submit(call_script, ordinal, arg)
        ordinal += 1
print('All tasks has been finished')

이전 코드의 출력은 다음과 같습니다.

Thread 1 argument: argumentsA
Thread 2 argument: argumentsB
Thread 1 Finished
Thread 2 Finished
Thread 3 argument: argumentsC
Thread 3 Finished
All tasks has been finished

장점 중 하나는 최대 동시 작업자를 설정하는 처리량을 제어할 수 있다는 것입니다.

대신 다중 처리를 사용하려면 프로세스 풀 실행기를 사용할 수 있습니다.

저는 입력 목록을 기반으로 한 목록 이해를 사용하는 것을 선호합니다.

inputs = [scriptA + argumentsA, scriptA + argumentsB, ...]
threads = [Thread(target=call_script, args=(i)) for i in inputs]
[t.start() for t in threads]
[t.join() for t in threads]

아래와 같은 클래스에서 병렬로 실행할 'n'개의 함수 또는 console_script를 추가하고 실행을 시작하고 모든 작업이 완료될 때까지 기다릴 수 있습니다.

from multiprocessing import Process

class ProcessParallel(object):
    """
    To Process the  functions parallely

    """    
    def __init__(self, *jobs):
        """
        """
        self.jobs = jobs
        self.processes = []

    def fork_processes(self):
        """
        Creates the process objects for given function deligates
        """
        for job in self.jobs:
            proc  = Process(target=job)
            self.processes.append(proc)

    def start_all(self):
        """
        Starts the functions process all together.
        """
        for proc in self.processes:
            proc.start()

    def join_all(self):
        """
        Waits untill all the functions executed.
        """
        for proc in self.processes:
            proc.join()


def two_sum(a=2, b=2):
    return a + b

def multiply(a=2, b=2):
    return a * b


#How to run:
if __name__ == '__main__':
    #note: two_sum, multiply can be replace with any python console scripts which
    #you wanted to run parallel..
    procs =  ProcessParallel(two_sum, multiply)
    #Add all the process in list
    procs.fork_processes()
    #starts  process execution 
    procs.start_all()
    #wait until all the process got executed
    procs.join_all()

방금 for 루프를 사용하여 생성된 모든 스레드를 기다려야 하는 동일한 문제를 발견했습니다.저는 방금 다음 코드를 사용해 보았습니다.완벽한 솔루션은 아닐 수도 있지만 테스트를 위한 간단한 솔루션이라고 생각했습니다.

for t in threading.enumerate():
    try:
        t.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err:
            continue
        else:
            raise

threading

메인 스레드 개체가 있습니다. 이것은 파이썬 프로그램의 초기 제어 스레드에 해당합니다.데몬 스레드가 아닙니다.

더미 스레드 개체가 생성될 수 있습니다.이것들은 "외계 스레드"에 해당하는 스레드 객체이며, C 코드에서 직접처럼 스레드 모듈 외부에서 시작된 제어 스레드입니다.더미 스레드 객체는 제한된 기능을 가지고 있으며, 항상 활성 및 대모닉으로 간주되며, 다음과 같을 수 없습니다.join()스레드의 에 절대. 외계 스레드의 종료를 탐지하는 것이 불가능하기 때문에 삭제되지 않습니다.

따라서 생성한 스레드 목록을 유지하는 데 관심이 없는 경우 이 두 가지 경우를 파악하려면 다음과 같이 하십시오.

import threading as thrd


def alter_data(data, index):
    data[index] *= 2


data = [0, 2, 6, 20]

for i, value in enumerate(data):
    thrd.Thread(target=alter_data, args=[data, i]).start()

for thread in thrd.enumerate():
    if thread.daemon:
        continue
    try:
        thread.join()
    except RuntimeError as err:
        if 'cannot join current thread' in err.args[0]:
            # catchs main thread
            continue
        else:
            raise

다음의 경우:

>>> print(data)
[0, 4, 12, 40]

아마도, 비슷한 것.

for t in threading.enumerate():
    if t.daemon:
        t.join()

join만 사용하면 스레드와 잘못된 긍정적 상호 작용이 발생할 수 있습니다.문서에 언급된 바와 같이:

시간 초과 인수가 있고 없음이 아닌 경우에는 작업의 시간 초과(초 또는 그 부분)를 지정하는 부동 소수점 번호여야 합니다.join()은 항상 None을 반환하므로 join() 후 isAlive()를 호출하여 시간 초과가 발생했는지 여부를 결정해야 합니다. 스레드가 아직 활성 상태이면 join() 호출이 시간 초과되었습니다.

및 예시적인 코드 조각:

threads = []
for name in some_data:
    new = threading.Thread(
        target=self.some_func,
        args=(name,)
    )
    threads.append(new)
    new.start()
    
over_threads = iter(threads)
curr_th = next(over_threads)
while True:
    curr_th.join()
    if curr_th.is_alive():
        continue
    try:
        curr_th = next(over_threads)
    except StopIteration:
        break

언급URL : https://stackoverflow.com/questions/11968689/python-multithreading-wait-till-all-threads-finished

반응형