>백엔드 개발 >파이썬 튜토리얼 >Python의 프로세스 관리: 병렬 프로그래밍의 기초

Python의 프로세스 관리: 병렬 프로그래밍의 기초

Patricia Arquette
Patricia Arquette원래의
2025-01-03 09:52:40133검색

Process Management in Python: Fundamentals of Parallel Programming

병렬 프로그래밍은 프로그램이 여러 프로세서 또는 코어에서 여러 작업을 동시에 실행할 수 있도록 하는 프로그래밍 모델입니다. 이 모델은 프로세서 리소스를 보다 효율적으로 사용하고 처리 시간을 단축하며 성능을 높이는 것을 목표로 합니다.

병렬 프로그래밍을 이미지로 설명하기 위해 문제가 있다고 가정해 보겠습니다. 병렬 처리를 시작하기 전에 이 문제를 더 작은 하위 부분으로 나눕니다. 우리는 이러한 하위 부분이 서로 독립적이며 서로에 대한 지식이 없다고 가정합니다. 각 하위 문제는 더 작은 작업이나 지침으로 변환됩니다. 이러한 작업은 병렬 작업에 적합한 방식으로 구성됩니다. 예를 들어 데이터 세트에 대해 동일한 작업을 수행하기 위해 많은 지침을 만들 수 있습니다. 그런 다음 이러한 작업은 다른 프로세서에 배포됩니다. 각 프로세서는 할당된 명령을 독립적으로 병렬로 처리합니다. 이 프로세스를 통해 전체 처리 시간이 크게 줄어들고 리소스를 보다 효율적으로 사용할 수 있습니다.

Python은 병렬 프로그래밍을 위한 여러 도구와 모듈을 제공합니다.

**다중 처리
**이를 통해 프로그램은 여러 프로세스를 동시에 실행할 수 있으므로 진정한 병렬성을 활용할 수 있습니다. 멀티프로세싱 모듈은 GIL(Global Interpreter Lock)의 한계를 극복하여 멀티 코어 프로세서에서 최대 성능을 달성할 수 있습니다.

GIL(Global Interpreter Lock)은 CPython이라는 널리 사용되는 Python 구현에 사용되는 메커니즘입니다. GIL은 한 번에 하나의 스레드만 Python 바이트코드를 실행할 수 있도록 허용합니다. 이는 Python에서 멀티스레딩을 사용할 때 실제 병렬성을 제한하는 구성입니다.

*제곱 및 세제곱 계산 예시
*

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

멀티프로세싱이 필요한 이유 멀티프로세싱의 필요성은 요리사와 주방에 비유하여 설명할 수 있습니다. 주방에서 혼자 요리하는 요리사를 단일 프로세스 프로그램으로 생각할 수 있습니다. 같은 주방에서 두 명 이상의 요리사가 함께 작업하는 경우를 다중 처리에 비유할 수 있습니다.

단일 프로세스 - 단일 요리

주방에는 요리사가 한 명뿐입니다. 이 요리사는 세 가지 다른 요리, 즉 전식 요리, 메인 코스, 디저트를 만들 것입니다. 각 요리는 차례로 만들어집니다:
스타터를 준비하고 완성합니다.
메인 코스로 넘어가서 마무리합니다.
드디어 디저트를 만드네요.
문제:

아무리 빠른 요리사라도 차례대로 돌아가며 주방에서 시간을 낭비하게 됩니다.
세 가지 요리를 동시에 조리해야 한다면 시간이 더 길어집니다.
다중 처리 - 많은 요리사

이제 같은 주방에 세 명의 요리사가 있다고 상상해 보세요. 각자 다른 요리를 준비하고 있습니다:
한 명의 요리사가 스타터를 만듭니다.
두 번째 요리사가 메인 요리를 준비합니다.
세 번째 요리사가 디저트를 만듭니다.
장점:

세 가지 요리가 동시에 만들어지므로 전체 시간이 대폭 단축됩니다.
각 요리사는 독립적으로 작업을 수행하며 다른 요리사의 영향을 받지 않습니다.
Python에서 프로세스 간 데이터 공유
Python에서는 multiprocessing 모듈을 사용하여 서로 다른 프로세스 간에 데이터를 공유할 수 있습니다. 그러나 각 프로세스는 자체 메모리 공간을 사용합니다. 따라서 프로세스 간 데이터를 공유하기 위해 특별한 메커니즘이 사용됩니다.

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

코드 샘플을 살펴보면 결과 목록이 비어 있는 것을 볼 수 있습니다. 그 주된 이유는 다중 처리로 생성된 프로세스가 기본 프로세스와 독립적으로 자체 메모리 공간에서 작동하기 때문입니다. 이러한 독립성으로 인해 하위 프로세스의 변경 사항은 기본 프로세스의 변수에 직접 반영되지 않습니다.

Python은 다음과 같은 데이터 공유 방법을 제공합니다.

**1. 공유 메모리
**값 및 배열 개체는 작업 간에 데이터를 공유하는 데 사용됩니다.
값: 단일 데이터 유형(예: 숫자)을 공유합니다.
배열: 배열된 데이터를 공유하는데 사용됩니다.

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

**2. 대기열
**프로세스 간 데이터 전송을 위해 FIFO(First In First Out) 구조를 사용합니다.
multiprocessing.Queue를 사용하면 여러 프로세스가 데이터를 보내고 받을 수 있습니다.

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**3. 파이프
**multiprocessing.Pipe는 두 프로세스 간의 양방향 데이터 전송을 제공합니다.
데이터 전송 및 수신에 모두 사용할 수 있습니다.

from multiprocessing import Process, Queue

def producer(queue):
    for i in range(5):
        queue.put(i)  # Kuyruğa veri ekle
        print(f"Üretildi: {i}")

def consumer(queue):
    while not queue.empty():
        item = queue.get()  
        print(f"Tüketildi: {item}")

if __name__ == "__main__":
    queue = Queue()

    producer_process = Process(target=producer, args=(queue,))
    consumer_process = Process(target=consumer, args=(queue,))

    producer_process.start()
    producer_process.join()

    consumer_process.start()
    consumer_process.join()

*프로세스 간 패딩
*
"프로세스 간 패딩"은 프로세스 메모리 구성이나 여러 프로세스 간에 공유되는 데이터에 액세스할 때 데이터 정렬 및 충돌 문제를 방지하기 위해 자주 사용됩니다.

이 개념은 캐시 라인 거짓 공유와 같은 경우에 특히 중요합니다. 여러 프로세스가 동시에 공유 메모리를 사용하려고 하면 잘못된 공유로 인해 성능이 저하될 수 있습니다. 이는 최신 프로세서에서 캐시 라인을 공유하기 때문입니다.

**프로세스 간 동기화
**Python의 다중 처리 모듈을 사용하면 여러 프로세스를 동시에 실행할 수 있습니다. 그러나 여러 프로세스가 동일한 데이터에 액세스해야 하는 경우 동기화를 사용하는 것이 중요합니다. 이는 데이터의 일관성을 보장하고 경쟁 조건과 같은 문제를 방지하는 데 필요합니다.

from multiprocessing import Process, Pipe

def send_data(conn):
    conn.send([1, 2, 3, 4])  
    conn.close()

if __name__ == "__main__":
    parent_conn, child_conn = Pipe()  

    process = Process(target=send_data, args=(child_conn,))
    process.start()

    print(f"Alınan veri: {parent_conn.recv()}")  # Veri al
    process.join()

잠금을 사용하면 한 번에 하나의 프로세스만 공유 데이터에 액세스할 수 있습니다.
잠금을 사용하는 프로세스가 완료되기 전에 다른 프로세스가 대기합니다.

**멀티스레딩

멀티스레딩은 프로그램이 여러 스레드를 동시에 실행할 수 있도록 하는 병렬 프로그래밍 모델입니다. 스레드는 동일한 프로세스 내에서 실행되고 리소스를 공유하여 더 빠르고 효율적인 처리를 목표로 하는 더 작고 독립적인 코드 단위입니다.
Python에서 스레딩 모듈은 멀티스레딩 애플리케이션을 개발하는 데 사용됩니다. 그러나 Python의 GIL(Global Interpreter Lock) 메커니즘으로 인해 멀티스레딩은 CPU 바인딩된 작업에 대해 제한된 성능을 제공합니다. 따라서 일반적으로 I/O 중심 작업에는 멀티스레딩이 선호됩니다.

스레드는 우리 프로그램의 명령 순서입니다.

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

**스레드 동기화
**스레드 동기화는 여러 스레드가 동일한 리소스에 동시에 액세스할 때 데이터 일관성과 순서를 보장하는 데 사용되는 기술입니다. Python에서 스레딩 모듈은 동기화를 위한 여러 도구를 제공합니다.

**스레드 동기화가 필요한 이유는 무엇입니까?
**경주 조건:

두 개 이상의 스레드가 동시에 공유 리소스에 액세스하면 데이터 불일치가 발생할 수 있습니다.
예를 들어, 한 스레드가 데이터를 읽는 동안 다른 스레드가 동일한 데이터를 업데이트할 수 있습니다.
*데이터 일관성:
*

공유 리소스가 올바르게 업데이트되도록 하려면 스레드 간 조정이 필요합니다.
Python의 동기화 도구 예
**1. 자물쇠
**스레드가 잠금을 획득하면 다른 스레드가 동일한 리소스에 액세스하기 전에 잠금이 해제될 때까지 기다립니다.

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

2-이벤트

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**결론:
**스레드 동기화는 스레드가 공유 리소스에 액세스할 때 데이터 불일치를 방지하는 데 중요합니다. Python에서는 Lock, RLock, Semaphore, Event 및 Condition과 같은 도구가 동기화 요구 사항에 따라 효과적인 솔루션을 제공합니다. 사용할 도구는 애플리케이션 요구 사항과 동기화 요구 사항에 따라 다릅니다.

위 내용은 Python의 프로세스 관리: 병렬 프로그래밍의 기초의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:PyTorch의 서브다음 기사:PyTorch의 서브