Python 다중 프로세스, 다중 스레드 효율 비교

Python계에는 불문율의 준칙이 있다. 계산 집약형 작업은 다중 프로세스에 적합하고 IO 집약형 작업은 다중 스레드에 적합하다.이 편을 비교해 보겠습니다.
일반적으로 다중 스레드는 다중 프로세스에 비해 장점이 있다. 왜냐하면 하나의 프로세스를 만드는 비용이 비교적 크지만python에 GIL이라는 큰 자물쇠가 존재하기 때문에 계산 집약형 작업을 수행할 때 다중 스레드는 실제적으로 단일 스레드일 수밖에 없다.또한 스레드 사이의 전환 비용으로 인해 다중 스레드는 실제 단일 스레드보다 느리기 때문에python에서 계산 집약형 작업은 일반적으로 다중 프로세스를 사용합니다. 각 프로세스는 각자의 GIL이 있기 때문에 서로 간섭하지 않습니다.
그러나 IO 집약형 작업에서 CPU는 항상 대기 상태에 있고 운영체제는 외부 환경과 자주 상호작용을 해야 한다. 예를 들어 파일 읽기, 네트워크 간 통신 등이다.이 기간 동안 GIL이 방출되기 때문에 진정한 다중 스레드를 사용할 수 있다.
이상은 이론이다. 다음은 간단한 시뮬레이션 테스트를 한다. 대량의 계산용math.sin() + math.cos() 으로 대체하고 IO 밀집형용time.sleep() 으로 시뮬레이션한다.Python에서는 여러 가지 방법으로 다중 프로세스와 다중 루틴을 실현할 수 있습니다. 여기서 효율 차이가 있는지 함께 살펴보겠습니다.
  • 다중 프로세스:joblib.multiprocessing, multiprocessing.Pool, multiprocessing.apply_async, concurrent.futures.ProcessPoolExecutor
  • 다중 스레드:joblib.threading, threading.Thread, concurrent.futures.ThreadPoolExecutor
  • 
    from multiprocessing import Pool
    from threading import Thread
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
    import time, os, math
    from joblib import Parallel, delayed, parallel_backend
    
    
    def f_IO(a): # IO  
     time.sleep(5)
    
    def f_compute(a): #  
     for _ in range(int(1e7)):
      math.sin(40) + math.cos(40)
     return
    
    def normal(sub_f):
     for i in range(6):
      sub_f(i)
     return
    
    def joblib_process(sub_f):
     with parallel_backend("multiprocessing", n_jobs=6):
      res = Parallel()(delayed(sub_f)(j) for j in range(6))
     return
    
    
    def joblib_thread(sub_f):
     with parallel_backend('threading', n_jobs=6):
      res = Parallel()(delayed(sub_f)(j) for j in range(6))
     return
    
    def mp(sub_f):
     with Pool(processes=6) as p:
      res = p.map(sub_f, list(range(6)))
     return
    
    def asy(sub_f):
     with Pool(processes=6) as p:
      result = []
      for j in range(6):
       a = p.apply_async(sub_f, args=(j,))
       result.append(a)
      res = [j.get() for j in result]
    
    def thread(sub_f):
     threads = []
     for j in range(6):
      t = Thread(target=sub_f, args=(j,))
      threads.append(t)
      t.start()
     for t in threads:
      t.join()
    
    def thread_pool(sub_f):
     with ThreadPoolExecutor(max_workers=6) as executor:
      res = [executor.submit(sub_f, j) for j in range(6)]
    
    def process_pool(sub_f):
     with ProcessPoolExecutor(max_workers=6) as executor:
      res = executor.map(sub_f, list(range(6)))
    
    def showtime(f, sub_f, name):
     start_time = time.time()
     f(sub_f)
     print("{} time: {:.4f}s".format(name, time.time() - start_time))
    
    def main(sub_f):
     showtime(normal, sub_f, "normal")
     print()
     print("------   ------")
     showtime(joblib_process, sub_f, "joblib multiprocess")
     showtime(mp, sub_f, "pool")
     showtime(asy, sub_f, "async")
     showtime(process_pool, sub_f, "process_pool")
     print()
     print("-----   -----")
     showtime(joblib_thread, sub_f, "joblib thread")
     showtime(thread, sub_f, "thread")
     showtime(thread_pool, sub_f, "thread_pool")
    
    
    if __name__ == "__main__":
     print("-----   -----")
     sub_f = f_compute
     main(sub_f)
     print()
     print("----- IO   -----")
     sub_f = f_IO
     main(sub_f)
    결과:
    
    -----   -----
    normal time: 15.1212s
    
    ------   ------
    joblib multiprocess time: 8.2421s
    pool time: 8.5439s
    async time: 8.3229s
    process_pool time: 8.1722s
    
    -----   -----
    joblib thread time: 21.5191s
    thread time: 21.3865s
    thread_pool time: 22.5104s
    
    
    
    ----- IO   -----
    normal time: 30.0305s
    
    ------   ------
    joblib multiprocess time: 5.0345s
    pool time: 5.0188s
    async time: 5.0256s
    process_pool time: 5.0263s
    
    -----   -----
    joblib thread time: 5.0142s
    thread time: 5.0055s
    thread_pool time: 5.0064s
    위의 모든 방법은 6개의 프로세스/스레드를 통일적으로 만들었는데 그 결과 집약적 작업의 속도를 계산하는 것이다. 다중 프로세스 > 단일 프로세스/스레드 > 다중 스레드, IO 집약적 작업 속도: 다중 스레드 > 다중 프로세스 > 단일 프로세스/스레드이다.
    이상은Python 다중 프로세스, 다중 스레드 효율 비교의 상세한 내용입니다. 더 많은Python 다중 프로세스, 다중 스레드에 대한 자료는 저희 다른 관련 글을 주목해 주십시오!

    좋은 웹페이지 즐겨찾기