데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      [Python] Process간 Numpy Array 공유하기 -1편

      Teus 22.03.04
      6,733 10 1

      이번 포스팅은 Numpy와 Python의 multiprocessing과 관련된 내용을 다룹니다.

       

      이전 두개의 포스팅으로, Numpy가 왜 빠른지 알아보았습니다. 

      하지만 Numpy가 아무리 빨라도 일반적인 패턴의 프로그래밍에서는 CPU를 하나 이상 사용할 수 없습니다.

       

      이제는 식상하지만, CPU의 발전은 High Frequency CPU보다 MultiCore CPU 방향으로 발전되고 있습니다.

       

      인텔의 최신 CPU인 Alder Lake Cpu의 Die 사진(CPU Core가 무려 16개 입니다)

      출처 : CapFrameX - Alder Lake-S 12900K is the new Gaming King - Blog

       

      일반적인 프로그래밍을 할 경우 이런 다수의 코어를 사용하지 못하고, 결국 하나의 코어만 사용하게 되는 상황이 발생합니다.

       

      아무리 비싼 CPU를 사봤자 I사와 A사에 돈만 갔다드리는 꼴이 되어버리죠.

      (물론 다수의 프로그램을 동시에 돌리는 측면에서는 유리합니다)

       

      이런 멀티코어를 활용할 수 있는 방법으로 대부분의 Programming Language는 멀티Thread 프로그래밍을 지원합니다.

       

      Python 역시 threading 내장모듈을 통해서 멀티Thread를 지원합니다.

       

      하지만 Python 의 경우 악명높은 GIL(Global Interpreter Lock)때문에 한번에 1개의 Thread만 실행이 가능합니다. 다수의 코어를 사용하더라도 동시에 명령어가 실행되는 코어는 오직 하나가 됩니다.

       

      GIL에 대한 Article : What Is the Python Global Interpreter Lock (GIL)? – Real Python

       

      때문에 threading 모듈을 사용할 경우 I/O 작업의 이득 외에는 일반적인 프로그래밍과 차이점이 없어집니다. 이는 Python의 공식 문서에서 확인할 수 있습니다.

       

      공식 문서에서 소개된 Python Threading 모듈의 한계점

      출처 : threading — 스레드 기반 병렬 처리 — Python 3.10.2 문서

       

      그래서, Python에서는 Thread보다 더 높은 Level의 Process를 새로 만들어서 멀티코어를 활용할 수가 있습니다.

      (Process는 독립된 Python Shell이라고 생각할 수 있습니다)

       

      하지만 여기서 문제가 발생합니다. Python Shell끼리 서로 다른 작업을 하면 상관없지만, 같은 Data를 가지고 작업해야하는 순간은 언제나 찾아옵니다.

       

      하지만, 당연하게도 서로다른 Python Shell끼리는 변수가 공유되지 않습니다.

       

      같은 변수명을 서로 다른 Python Shell에서 접근할 경우

       

       

      Multiprocessing 모듈의 경우 Process를 새로 만들 때 Process마다 변수를 부여할 수가 있습니다.

       

      Python 공식문서의 Multiprocessing.Process 사용 패턴

      from multiprocessing import Process
      
      def f(name):
          print('hello', name)
      
      if __name__ == '__main__':
          #Process를 만들 때 args를 통해서 매개변수를 받아들인다.
          p = Process(target=f, args=('bob',))
          p.start()
          p.join()

       

      하지만 Python의 경우 상황이 녹녹하지 않습니다. 새로운 Process가 만들어 지기 때문에 매개변수에 PyObject를 줄 경우 PyObject의 주소가 전달되는것이 아니라 Data가 복사되어 오버헤드가 발생하게 됩니다!

       

      Process생성&데이터 전달의 오버헤드 발생으로 안쓴게 더 유리한 예시

      import multiprocessing as mp
      import numpy as np
      import time
      
      def mul_foo(arr, threadid):
          arr[:] = threadid
          return arr
      
      if __name__ == "__main__":
          core = 4
          data_len = 10000000
          st = time.time()
          main_np_arr = np.array([None for i in range(data_len)])
          args = ([main_np_arr[i*int(data_len/core):(i+1)*int(data_len/core)], i] for i in range(core))
          with mp.Pool(4) as pool:
              print(pool.starmap(mul_foo, args))
          print("Multi time : ", time.time()-st)
          # Multi time :  3.552473783493042
      
          st = time.time()
          main_np_arr_normal = np.array([None for i in range(data_len)])
          for i in range(4):
              main_np_arr_normal[i*int(data_len/core):(i+1)*int(data_len/core)] = i
          print(main_np_arr_normal)
          print("Normal time : ", time.time()-st)
          # Normal time :  1.3533821105957031

       

      다른 대안으로 Multiprocessing Queue, Value, Manager를 사용하여 Process간 공유가 가능하나, 앞의 3가지 방법 모두 단점이 존재합니다.

      1. Multiprocessing Queue : Queue를 통해서 Process간 Data이동. 하지만 GIL때문에 Data이동 시 오버헤드 발생(결국 데이터가 복사가 됩니다)

      2. Multiprocessing Value : Process끼리 공유가 가능한 Shared Object. 하지만 Ctypes 객체 이외에 PyObject는 불가능(처음 선언은 가능하나, 다른 Process에서 읽을려면 오류가 발생합니다(이는 공식문서에서도 명시되어 있습니다). 때문에 Ctypes 외 다른 데이터를 사용하기가 어렵습니다.

       

      Python 공식 문서에 명시된 MultiProcessing Value의 한계점

       

       

      3. Multiprocessing Manager : Process간 Proxy를 이용해서 Data를 교환 = 느립니다....

      Python에서 Process간 Big Data를 원활하게 활용할 방법은 없는것일까요?

       

      포스팅이 길어진 관계로 다음 포스팅에서 Numpy의 PyArray_FromBuffer와 Python shared_memory를 활용한 Data공유 방법에 대해서 기술하겠습니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      Teus 님의 최신 블로그

      더보기
      동영상 기고하기