Python 다 중 스 레 드 와 다 중 프로 세 스 에 관 한 지식 총화

프로 세 스
  • 프로 세 스 는 실행 중인 프로그램 으로 자원 배분 의 최소 단위 입 니 다.운영 체 제 는 프로 세 스 단위 로 저장 공간 을 분배 하고 프로 세 스 는 독립 된 주소 공간,메모리,데이터 스 택 등
  • 을 가지 고 있 습 니 다.
  • 운영 체제 관리 모든 프로 세 스 의 실행,자원 배분
  • 은 fork 또는 spawn 방식 으로 새로운 프로 세 스 를 파생 시 킬 수 있 고 새로운 프로 세 스 도 자신의 독립 된 메모리 공간
  • 이 있 습 니 다.
  • 프로 세 스 간 통신 방식(IPC,Inter-Process Communication)은 정 보 를 공유 하고 데이터 공 유 를 실현 하 며 파이프,신호,소켓,공유 메모리 구역 등 을 포함한다.
  • 2.스 레 드 가 무엇 입 니까?
  • 스 레 드 는 CPU 가 관리 하 는 최소 단위
  • 이다.
  • 하나의 프로 세 스 는 여러 개의 스 레 드 를 가 질 수 있 습 니 다.
  • 같은 프로 세 스 에서 실행 되 고 같은 컨 텍스트
  • 을 공유 합 니 다.
  • 스 레 드 간 의 정보 공유 와 통신 은
  • 보다 쉽다.
  • 다 중 스 레 드 병행 실행
  • 동기 화 원 어
  • 이 필요 합 니 다.
    병발

    병발 은 보통 I/O 조작 이 빈번 한 장면 에 사용 되 고 병행 은 CPU heavy 장면 에 더 많이 사용 된다.
    3.1 동시 다발
    동시 다발(concurrency)은 같은 시간 에 하나의 명령 만 실행 할 수 있 고 여러 스 레 드 에 대응 하 는 명령 이 빠르게 번갈아 실행 되 며 스 레 드/작업 간 에 서로 전환 되 는 것 을 말한다.
  • 프로세서 가 먼저 스 레 드 A 의 명령 을 한 동안 실행 한 다음 에 스 레 드 B 의 명령 을 한 동안 실행 한 다음 에 스 레 드 A 로 자 르 고 빠 른 교대 로 실행 합 니 다.
  • 프로세서 전환 과정 에서 문맥 전환 작업 을 하고 여러 스 레 드 간 전환 과 실행 을 합 니 다.이 전환 과정 은 매우 빨 라 서 거시적인 측면 에서 여러 스 레 드 가 동시에 실행 되 는 것 처럼 보 입 니 다.
  • 모든 스 레 드 의 실행 은 이 프로세서 의 시간 세 션 을 차지 합 니 다.같은 시간 에 하나의 스 레 드 만 실 행 됩 니 다.
  • 3.2 병렬
    병렬(parallel)은 같은 시간 에 여러 개의 명령 이 여러 프로세서 에서 동시에 실행 되 는 것 을 말한다.
  • 거시적인 측면 에서 든 미시적 인 측면 에서 든 여러 개의 스 레 드 는 모두 같은 시간 에 함께 집행 된다.
  • 병행 은 다 중 프로세서 시스템 에 만 존재 할 수 있 으 며,핵 하나만 있 으 면 병행 이 불가능 합 니 다.단일 프로세서 와 다 중 프로세서 시스템 에 병발 할 수 있 으 며,하나의 핵 이 병발 할 수 있다.
  • 주의:구체 적 으로 병발 하 느 냐 병행 하 느 냐 는 운영 체제 의 스케줄 에 달 려 있 습 니 다.
    4.다 중 스 레 드 적용 장면
    다 중 스 레 드/다 중 프로 세 스 는 병발 문 제 를 해결 하 는 대표 적 인 모델 중 하나 입 니 다.
    한 프로그램 프로 세 스 에서 일부 작업 은 비교적 시간 이 걸 리 거나 기 다 려 야 한다.예 를 들 어 데이터 베 이 스 를 기다 리 는 조회 결과 의 귀환,웹 결과 의 응답 을 기다 리 는 것 이다.이 스 레 드 는 기다 리 는 과정 에서 처리 장 치 는 다른 조작 을 수행 하여 전체적으로 실행 효율 을 높 일 수 있다.
    예 를 들 어 네트워크 파충 류 는 서버 에 요청 을 한 후에 서버 의 응답 이 돌아 오 기 를 기 다 려 야 합 니 다.이런 작업 은 IO 밀집 형 작업 에 속 합 니 다.이러한 작업 에 대해 다 중 스 레 드 를 사용 하면 특정한 스 레 드 가 기다 리 는 과정 에서 다른 작업 을 처리 하여 전체적인 기어 오 르 는 효율 을 높 일 수 있 습 니 다.
    또 하나의 임 무 는 밀집 형 임 무 를 계산 하거나 CPU 밀집 형 임무 라 고 부른다.작업 의 실행 은 줄곧 프로세서 의 참여 가 필요 하 다.다 중 스 레 드 를 사용 하면 하나의 프로세서 가 하나의 컴 퓨 팅 밀집 형 작업 에서 다른 컴 퓨 팅 밀집 형 작업 으로 전환 되 고 프로세서 가 멈 추 지 않 으 며 전체적인 시간 을 절약 하지 않 습 니 다.스 레 드 수가 너무 많 으 면 프로 세 스 컨 텍스트 전환 은 대량의 자원 을 차지 하고 전체 효율 이 낮 아 집 니 다.
    따라서 임무 가 모두 밀집 형 임 무 를 계산 하 는 것 이 아니라면 우 리 는 다 중 스 레 드 를 사용 하여 프로그램의 전체적인 집행 효율 을 높 일 수 있다.특히 인터넷 파충류 와 같은 IO 밀집 형 임무 에 있어 다 중 스 레 드 를 사용 하면 프로그램의 전체적인 기어 오 르 는 효율 을 크게 향상 시 킬 수 있 고 다 중 스 레 드 는 IO 밀집 형 임무 에 만 적합 하 다.
    파 이 썬 GIL
    Python 에서 GIL 의 제한 으로 인해 단일 핵 이 든 다 핵 조건 이 든 같은 시간 에 하나의 스 레 드 만 실행 할 수 있 기 때문에 Python 다 중 스 레 드 는 다 핵 병행 의 장점 을 발휘 하지 못 합 니 다.
    GIL 은 Global Interpreter Lock(전역 해석 기 잠 금)이 라 고 불 리 며 Python 해석 기 CPython 의 기술 용어 로 Python 의 아버지 가 데이터 안전 을 위해 설계 한 것 입 니 다.
    CPython 은 인용 계 수 를 사용 하여 메모 리 를 관리 합 니 다.모든 Python 스 크 립 트 에서 만 든 인 스 턴 스 는 몇 개의 포인터 가 가리 키 는 지 기록 합 니 다.인용 계수 가 0 일 때 자동 으로 메모 리 를 방출 합 니 다.파 이 썬 해석 기 는 일정 시간 간격 으로 현재 스 레 드 에 GIL 을 강제 합 니 다.파 이 썬 3 이후 버 전의 간격 은 15 밀리초 입 니 다.
    Python 다 중 스 레 드 에서 모든 스 레 드 가 돌아 가면 서 실 행 됩 니 다:
  • 획득 GIL
  • 대응 스 레 드 를 실행 하 는 코드
  • 석방 GIL

  • 어떤 스 레 드 를 실행 하려 면 먼저 GIL 을 가 져 와 야 하고 Python 프로 세 스에 서 GIL 은 하나 밖 에 없어 서 다 핵 조건 에서 도 같은 시간 에 하나의 스 레 드 만 실행 할 수 있 습 니 다.모든 스 레 드 가 한 단락 을 실행 한 후에 다른 스 레 드 가 자원 을 사용 할 수 있 도록 GIL 을 방출 합 니 다.
    6.Python 다 중 스 레 드,다 중 프로 세 스 인 스 턴 스:CPU 밀집 형 작업
    6.1 단일 스 레 드
    CPU 밀집 형 작업 수행:
    
    import time
    import os
    
    def cpu_bound_task(n):
        print('    : {}'.format(os.getpid()))
        while n > 0:
            n -= 1
    
    if __name__ == "__main__":
        print('   : {}'.format(os.getpid()))
        start = time.time()
        for i in range(2):
            cpu_bound_task(100000000)
        end = time.time()
        print(f"  {end - start} ")
    
    출력:
    주 프로 세 스:10104
    현재 프로 세 스:10104
    현재 프로 세 스:10104
    10.8290328979219 초 소모
    6.2 다 중 스 레 드
    
    import os
    import threading
    import time
    
    
    def cpu_bound_task(n,i):
        print(f'    {threading.current_thread().name}:{os.getpid()} -   {i}')
        while n > 0:
            n -= 1
    
    if __name__=='__main__':
        start = time.time()
        print(f'   : {os.getpid()}')
        thread_list = []
        for i in range(1, 3):
            t = threading.Thread(target=cpu_bound_task, args=(100000000,i))
            thread_list.append(t)
    
        for t in thread_list:
            t.start()
    
        for t in thread_list:
            t.join()
    
        end = time.time()
        print(f"  {end - start} ")
    
  • start():시작 스 레 드
  • join():하위 스 레 드 가 끝 난 후에 야 주 프로그램 이 종료 되 고 모든 프로 세 스 의 실행 시간 을 계산 할 수 있 습 니 다.
  • 출력:
    주 루틴:1196
    서브 스 레 드 Thread-1:1196-퀘 스 트 1
    서브 스 레 드 Thread-2:196-퀘 스 트 2
    10.808091640472412 초 소모
    다 중 스 레 드 가 CPU 밀집 형 작업 성능 에 향상 되 지 않 은 것 을 발견 할 수 있 습 니 다.
    6.3 다 중 프로 세 스
    
    from multiprocessing import Process
    import os
    import time
    
    def cpu_bound_task(n,i):
        print(f'   : {os.getpid()} -   {i}')
        while n > 0:
            n -= 1
    
    if __name__=='__main__':
        print(f'   : {os.getpid()}')
        start = time.time()
        p1 = Process(target=cpu_bound_task, args=(100000000,1))
        p2 = Process(target=cpu_bound_task, args=(100000000,2))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
        end = time.time()
        print(f"  {end - start} ")
    
    출력:
    부모 프로 세 스:22636
    하위 프로 세 스:18072-퀘 스 트 1
    하위 프로 세 스:9580-퀘 스 트 2
    6.264242412933822632 초 소모
    Pool 클래스 를 사용 하여 다 중 프로 세 스 를 만 들 수도 있 습 니 다.
    
    from multiprocessing import Pool, cpu_count
    import os
    import time
    
    def cpu_bound_task(n,i):
        print(f'   : {os.getpid()} -   {i}')
        while n > 0:
            n -= 1
    
    if __name__=='__main__':
        print(f"CPU   :{cpu_count()}")
        print(f'   : {os.getpid()}')
        start = time.time()
        p = Pool(4)
        for i in range(2):
            p.apply_async(cpu_bound_task, args=(100000000,i))
        p.close()
        p.join()
        end = time.time()
        print(f"  {end - start} ")
    
    출력:
    CPU 커 널 수:8
    부모 프로 세 스:18616
    하위 프로 세 스:21452-퀘 스 트 0
    하위 프로 세 스:16712-퀘 스 트 1
    5.928101301193237 초 소모
    7.Python 다 중 스 레 드,다 중 프로 세 스 인 스 턴 스:IO 밀집 형 작업
    7.1 단일 스 레 드
    IO 밀집 형 퀘 스 트:
    
    def io_bound_task(self, n, i):
        print(f'   : {os.getpid()} -   {i}')
        print(f'IO Task{i} start')
        time.sleep(n)
        print(f'IO Task{i} end')
    
    if __name__=='__main__':
        print('   : {}'.format(os.getpid()))
        start = time.time()
        for i in range(2):
            self.io_bound_task(4,i)
        end = time.time()
        print(f"  {end - start} ")
    
    출력:
    주 프로 세 스:2780
    하위 프로 세 스:2780-퀘 스 트 0
    IO Task0 start
    IO Task0 end
    하위 프로 세 스:2780-퀘 스 트 1
    IO Task1 start
    IO Task1 end
    8.044940233323059 초 소모
    7.2 다 중 스 레 드
    
    print(f"CPU   :{cpu_count()}")
    print(f'   : {os.getpid()}')
    start = time.time()
    p = Pool(2)
    for i in range(2):
        p.apply_async(io_bound_task, args=(4, i))
    p.close()
    p.join()
    end = time.time()
    print(f"  {end - start} ")
    
    출력:
    CPU 커 널 수:8
    부모 프로 세 스:1396
    하위 프로 세 스:2712-퀘 스 트 0
    IO Task0 start
    하위 프로 세 스:10492-퀘 스 트 1
    IO Task1 start
    IO Task0 endIO Task1 end
    시간 소모 4.2011398162842 초
    IO 밀집 형 임무 에 대해 Python 다 중 스 레 드 가 현저히 향상 되 었 음 을 알 수 있다.
    7.3 다 중 프로 세 스
    
    print(f'   : {os.getpid()}')
    start = time.time()
    p1 = Process(target=io_bound_task, args=(4, 1))
    p2 = Process(target=io_bound_task, args=(4, 2))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    end = time.time()
    print("  {} ".format((end - start)))
    
    출력:
    부모 프로 세 스:12328
    하위 프로 세 스:12452-퀘 스 트 2
    IO Task2 start
    하위 프로 세 스:16896-퀘 스 트 1
    IO Task1 start
    IO Task1 endIO Task2
    end
    시간 소모 4.1241302490234375 초
    7.4 협정
    IO 형 임 무 는 협 정 을 사용 할 수 있 고 협 정 은 스 레 드 보다 경량급 이 며 한 스 레 드 는 여러 개의 협 정 을 가 질 수 있 으 며 협 정 은 사용자 상태 에서 실 행 될 수 있 으 며 완전히 프로그램 에 의 해 제어 된다.일반적으로 스 레 드 의 수량 이 많 을 수록 협 정 성능 의 장점 이 뚜렷 하 다.여기 서 Python 협 정 을 소개 하지 않 겠 습 니 다.아래 Python 코드 는 협 정의 실현 방식 중 하나 입 니 다.
    
    import asyncio
    import time
    
    async def io_bound_task(self,n,i):
        print(f'   : {os.getpid()} -   {i}')
        print(f'IO Task{i} start')
        # time.sleep(n)
        await asyncio.sleep(n)
        print(f'IO Task{i} end')
    
    if __name__ == '__main__':        
        start = time.time()
        loop = asyncio.get_event_loop()
        tasks = [io_bound_task(4, i) for i in range(2)]
        loop.run_until_complete(asyncio.wait(tasks))
        loop.close()
        end = time.time()
        print(f"  {end - start} ")
    
    출력:
    하위 프로 세 스:5436-퀘 스 트 1
    IO Task1 start
    하위 프로 세 스:5436-퀘 스 트 0
    IO Task0 start
    IO Task1 end
    IO Task0 end
    4.008626461029053 초 소모
    8.총화
    Python 은 GIL 잠 금 이 존재 하기 때문에 다 중 프로 세 스 의 장점 을 이용 할 수 없습니다.다 중 핵 을 진정 으로 이용 하려 면 JPython(자바 가 구현 한 Python 해석 기)과 같은 GIL 이 없 는 해석 기 를 다시 쓸 수 있 습 니 다.
    어떤 Python 라 이브 러 리 는 C 언어 로 이 루어 집 니 다.예 를 들 어 NumPy 라 이브 러 리 는 GIL 의 영향 을 받 지 않 습 니 다.실제 작업 에서 성능 에 대한 요구 가 높 으 면 C++를 사용 하여 실현 한 다음 에 Python 호출 인 터 페 이 스 를 제공 할 수 있 습 니 다.또 자바 언어 에 도 GIL 제한 이 없다.
    다 중 스 레 드 작업 에 대해 스 레 드 수량 이 많 으 면 Python 협 정 을 사용 하 는 것 을 권장 합 니 다.다 중 스 레 드 보다 효율 이 높 습 니 다.
    파 이 썬 다 중 스 레 드 와 다 중 프로 세 스 에 관 한 지식 을 정리 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 파 이 썬 다 중 스 레 드 와 다 중 프로 세 스 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기