[파읎썬] Multiprocessing, Multithreading 자원 분할 및 할당

Posted by Euisuk's Dev Log on February 19, 2024

[파읎썬] Multiprocessing, Multithreading 자원 분할 및 할당

원볞 게시Ꞁ: https://velog.io/@euisuk-chung/파읎썬-Multiprocessing-Multithreading-자원-분할-및-할당

멀티프로섞싱곌 멀티슀레딩에서 자원 분할곌 작업 할당은 각각 닀륎게 읎룚얎집니닀. 읎 곌정을 읎핎하Ʞ 위핎서는 뚌저, 컎퓚터의 자원(특히 CPU와 메몚늬) 사용 방식곌 작업의 종류(예: CPU 집앜적 vs. I/O 집앜적)륌 고렀핎알 합니닀.

멀티프로섞싱(Multiprocessing)의 자원 분할

멀티프로섞싱에서는 각 프로섞슀가 독늜된 메몚늬 공간을 가집니닀. 읎는 각 프로섞슀가 시슀템의 자원을 독늜적윌로 할당받는닀는 의믞입니닀. CPU 자원의 분할은 욎영 첎제의 슀쌀쀄러에 의핎 ꎀ늬되며, 여러 프로섞슀 간에 CPU 시간을 공정하게 분배합니닀.

작업읎 N개의 프로섞슀에 분배될 때, 읎론적윌로는 각 프로섞슀에 작업의 1/N을 할당할 수 있습니닀. 하지만 싀제 분할은 작업의 성격, 프로섞슀의 싀행 상태, 시슀템의 닀륞 요구 사항 등에 따띌 달띌질 수 있습니닀. 예륌 듀얎, ì–Žë–€ 프로섞슀는 CPU륌 많읎 사용하는 반멎, 닀륞 프로섞슀는 대Ʞ 상태에 있을 수 있습니닀.

멀티슀레딩(Multithreading)의 자원 분할

멀티슀레딩에서는 몚든 슀레드가 프로섞슀의 메몚늬 공간을 공유합니닀. 따띌서, 메몚늬 자원은 별도로 분할되지 않고, 몚든 슀레드가 같은 메몚늬 영역에 접귌할 수 있습니닀. CPU 자원의 겜우, 욎영 첎제의 슀레드 슀쌀쀄러가 각 슀레드에 CPU 시간을 할당합니닀.

슀레드 간의 작업 분할은 프로섞슀 낎에서 읎룚얎지며, 슀레드가 수행하는 작업은 음반적윌로 더 작고, 구첎적읞 작업 닚위로 나누얎집니닀. 멀티슀레딩 환겜에서는 I/O 작업읎 진행되는 동안 닀륞 슀레드가 CPU륌 사용할 수 있얎, 전첎적읞 프로귞랚의 횚윚성을 높음 수 있습니닀.

⭐ (Q&A) 여Ʞ서 잠깐!!

Q. 멀티프로섞슀에서 프로섞슀A와 프로섞슀B가 있닀고 가정핎볎겠습니닀. 귞럌 4읎띌는 가용 자원읎 있을때 만앜 프로섞슀A가 뚌저 끝나멎 나뚞지 프로섞슀읞 프로섞슀B가 낚은 자원 4개륌 ë‹€ 쓰도록 바뀌도록 자동윌로 할당핎죌나요?

A. 싀제로 프로섞슀A가 종료되얎 자원읎 반환될 때, 프로섞슀B가 자동윌로 몚든 자원을 활용하도록 시슀템읎 재조정되는 것은 볎장되지 않습니닀. 자원의 재할당은 욎영 첎제의 슀쌀쀄링 알고늬슘곌 정책에 따띌 결정되며, 닀륞 대Ʞ 쀑읞 프로섞슀나 시슀템의 전반적읞 자원 ꎀ늬 전략에 의핎 영향을 받습니닀. 프로섞슀B가 추가 자원을 활용하렀멎, 핎당 프로섞슀가 병렬 처늬륌 지원하고 추가 CPU 윔얎륌 횚윚적윌로 활용할 수 있는 구조로 섀계되얎알 합니닀.

⭐ 추가 섀명: 자원 할당의 동작 방식

✅ CPU 윔얎 할당: 가용 자원읎 CPU 윔얎띌고 할 때, 각 프로섞슀는 욎영 첎제에 의핎 하나 읎상의 CPU 윔얎에 할당될 수 있습니닀. 프로섞슀A와 프로섞슀B가 각각 2개의 CPU 윔얎륌 사용하고 있닀멎, 읎는 프로섞슀가 싀행되는 동안 동시에 2개의 작업을 수행할 수 있음을 의믞합니닀.

✅ 동적 재할당: 프로섞슀A가 작업을 완료하고 종료되멎, ê·ž 프로섞슀에 할당되었던 자원(여Ʞ서는 CPU 윔얎)은 시슀템에 반환됩니닀. 읎후 욎영 첎제의 슀쌀쀄러는 읎제 사용 가능한 자원을 닀시 분배할 수 있게 됩니닀. 하지만, 자동윌로 프로섞슀B가 나뚞지 자원을 몚두 사용하도록 할당받는 것은 자동윌로 읎룚얎지지 않습니닀. ✅ 자원의 재할당 조걎: 프로섞슀B가 추가적읞 CPU 윔얎륌 사용할 수 있게 되는지 여부는 여러 요소에 의핎 결정됩니닀. 읎는 욎영 첎제의 슀쌀쀄링 정책, 프로섞슀의 우선순위, 귞늬고 프로섞슀B가 추가 자원을 횚곌적윌로 활용할 수 있는지(예: 병렬 처늬가 가능한 작업읞지)에 따띌 달띌질 수 있습니닀. ✅ 자원 사용의 최적화: 대부분의 현대 욎영 첎제는 시슀템 자원을 횚윚적윌로 활용하Ʞ 위한 복잡한 슀쌀쀄링 알고늬슘을 사용합니닀. 프로섞슀A가 종료되얎 자원읎 반환되멎, 읎 자원은 시슀템의 닀륞 대Ʞ 쀑읞 프로섞슀에 할당될 수 있습니닀. 귞러나, 특정 프로섞슀가 자동윌로 몚든 가용 자원을 독점하도록 시슀템읎 재조정하는 것은 음반적읞 겜우가 아닙니닀.


작업 할당 방식

싀제 작업 할당은 애플늬쌀읎션 레벚에서 개발자가 결정합니닀. 멀티프로섞싱읎나 멀티슀레딩을 사용할 때, 각각의 프로섞슀나 슀레드에 할당할 작업의 크Ʞ와 범위는 프로귞랚의 구조와 요구 사항에 따띌 달띌집니닀. 예륌 듀얎, 데읎터 처늬 작업을 여러 프로섞슀에 분배할 때는 각 프로섞슀가 처늬할 데읎터의 양을 균등하게 나누거나, 특정 조걎에 맞는 데읎터륌 할당하는 방식윌로 분할할 수 있습니닀.

멀티프로섞싱곌 멀티슀레딩 몚두 작업의 병렬 처늬륌 통핎 성능을 향상시킀지만, ê·ž 구현 방식곌 사용 사례는 크게 닀늅니닀. 멀티프로섞싱은 독늜적읞 작업읎 많고, 각 작업읎 상당한 양의 CPU 자원을 필요로 할 때 유늬하며, 멀티슀레딩은 작업 간에 자원을 공유핎알 하거나 I/O 바욎드 작업읎 많을 때 횚곌적입니닀.

작업 할당곌 자원 분배 방식에 대핮 더 자섞히 섀명하겠습니닀. Ʞ볞적윌로, 멀티프로섞싱곌 멀티슀레딩 환겜에서의 자원 할당은 자동곌 수동(개발자 지정) 방식을 몚두 포핚할 수 있습니닀.

자동 할당(시슀템)

  • 가용 자원의 자동 분배: 욎영 첎제의 슀쌀쀄러가 프로섞슀나 슀레드에 대핮 CPU 시간을 자동윌로 할당합니닀. 읎 겜우, 슀쌀쀄러는 시슀템의 현재 부하, 프로섞슀의 우선순위, 프로섞슀의 상태(싀행 쀑, 대Ʞ 쀑 등)와 같은 여러 요읞을 고렀하여 자원을 분배합니닀. 디폎튞로, 시슀템은 가능한 공정하게 자원을 분배하렀고 시도하지만, 읎는 “1/N”읎띌는 고정 비윚로 정확히 분배된닀는 의믞는 아닙니닀.

수동 할당(개발자 지정)

  • 개발자에 의한 명시적 분배: 개발자는 프로귞랚의 요구 사항곌 작업의 특성을 고렀하여, 각 프로섞슀나 슀레드에 할당될 작업의 양읎나 자원의 사용을 명시적윌로 지정할 수 있습니닀. 예륌 듀얎, 데읎터 처늬 작업을 여러 프로섞슀에 분배할 때 특정 Ʞ쀀에 따띌 작업을 나눌 수 있윌며, 읎는 작업의 횚윚성곌 싀행 시간에 영향을 믞칠 수 있습니닀.

멀티프로섞싱 자원 할당 예시

읎 예시에서는 대량의 데읎터륌 4개의 청크로 나누고, 각 청크륌 별도의 프로섞슀에 할당하여 병렬로 처늬합니닀. 읎는 개발자가 작업의 분배륌 명시적윌로 지정한 겜우입니닀.

1
2
3
4
5
6
7
8
9
10
11
12
13
from multiprocessing import Pool

def my_task(data_chunk):
    # 복잡한 계산 수행
    result = sum(data_chunk)
    return result

if __name__ == "__main__":
    data = range(1000000)  # 대량의 데읎터
    chunks = [data[i::4] for i in range(4)]  # 데읎터륌 4개의 청크로 나눔

    with Pool(4) as p:  # 4개의 프로섞슀 풀 생성
        results = p.map(my_task, chunks)  # 각 청크륌 별도의 프로섞슀에 할당

위 파읎썬 윔드에서 multiprocessing.Pool을 사용하여 멀티프로섞싱을 구현할 때, 자원 할당은 닀음곌 같읎 읎룚얎집니닀:

프로섞슀 풀곌 CPU 윔얎 할당

  • 프로섞슀 풀 생성: Pool(4)에 의핎 4개의 별도 프로섞슀가 생성됩니닀. 읎는 멀티프로섞싱을 위한 프로섞슀 풀로, 병렬 작업을 수행하Ʞ 위핎 쀀비된 프로섞슀 집합입니닀.
  • CPU 윔얎 사용: 시슀템에 8개의 CPU 윔얎가 있는 겜우, Pool(4)에 의핎 생성된 각 프로섞슀는 읎용 가능한 CPU 윔얎 쀑 하나륌 사용할 수 있게 됩니닀. 여Ʞ서 쀑요한 점은, 프로섞슀 풀에 의핎 생성된 프로섞슀 수가 시슀템의 CPU 윔얎 수볎닀 적Ʞ 때묞에, 몚든 프로섞슀가 동시에 싀행될 수 있윌며, 각각 별도의 CPU 윔얎에 할당될 가능성읎 높습니닀.

작업 처늬 방식

  • 병렬 처늬: 생성된 4개의 프로섞슀는 동시에 싀행되얎 각각 할당된 작업(데읎터 청크)을 처늬합니닀. 시슀템에 여유 윔얎가 충분히 있Ʞ 때묞에, 읎 프로섞슀듀은 서로 겜쟁 없읎 각자의 윔얎에서 싀행될 수 있습니닀.
  • 자원 활용 최적화: 8개의 윔얎 쀑 4개만 사용되므로, 나뚞지 윔얎는 시슀템의 닀륞 프로섞슀나 작업에 사용될 수 있습니닀. 읎는 멀티태슀킹 환겜에서 시슀템 자원을 횚윚적윌로 활용할 수 있게 핎쀍니닀.

(ì°žê³ ) 귞럌 얎떻게 핎알 가용 자원을 ë‹€ 쓞 수 있을까?

파읎썬의 multiprocessing 몚듈은 프로섞슀당 CPU 윔얎 수륌 직접 지정하는 Ʞ능을 직접 제공하지 않습니닀. CPU 윔얎의 할당곌 슀쌀쀄링은 욎영 첎제의 작업읎며, multiprocessing 띌읎람러늬는 읎러한 낮은 수쀀의 자원 ꎀ늬에 직접 개입하지 않습니닀. 귞러나, 전첎 CPU 윔얎륌 최대한 활용하렀는 목적읎띌멎, 작업을 더 많은 프로섞슀에 분배하거나 시슀템의 병렬 처늬 능력을 최대로 활용하는 방법을 고렀할 수 있습니닀. ã…€ 전첎 CPU 윔얎 사용하Ʞ : 시슀템에 있는 몚든 CPU 윔얎륌 사용하렀멎, multiprocessing.cpu\_count() 핚수륌 사용하여 시슀템에 있는 윔얎의 수륌 확읞하고, 읎륌 Pool의 읞자로 사용할 수 있습니닀. 읎 방법은 시슀템의 몚든 CPU 윔얎륌 활용하여 병렬 처늬륌 수행하렀는 겜우 유용합니닀. 아래 예시륌 찞고핎죌섞요 🀗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 전첎 CPU 윔얎 사용하Ʞ
from multiprocessing import Pool, cpu_count

def my_task(data_chunk):
    # 복잡한 계산 수행
    result = sum(data_chunk)
    return result

if __name__ == "__main__":
    data = range(1000000)  # 대량의 데읎터
    num_cores = cpu_count()  # 시슀템의 CPU 윔얎 수 확읞
    chunks = [data[i::num_cores] for i in range(num_cores)]  # 데읎터륌 CPU 윔얎 수만큌 청크로 나눔

    with Pool(num_cores) as p:  # 시슀템의 몚든 CPU 윔얎 사용
        results = p.map(my_task, chunks)

멀티슀레딩 자원 할당 예시

읎 멀티슀레딩 예시에서는 전첎 작업 범위륌 4개로 나누얎 각 슀레드가 처늬하도록 합니닀. 읎러한 방식은 각 슀레드가 처늬할 데읎터의 양을 명확하게 지정할 수 있Ʞ 때묞에, 작업의 분배가 고륎게 읎룚얎지도록 할 수 있습니닀.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import threading

def my_task(start, end):
    # 범위 낎의 숫자 합계 계산
    result = sum(range(start, end))
    print(f"Result: {result}")

threads = []
for i in range(4):
    # 전첎 범위륌 4개의 부분윌로 나누얎 각 슀레드에 할당
    t = threading.Thread(target=my_task, args=(250000*i, 250000*(i+1)))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

제시된 예시 윔드에서는 각 슀레드가 처늬하는 데읎터의 양을 균등하게 분배하였습니닀. 읎는 각 작업 닚위가 동음한 자원을 소비한닀고 가정했을 때 유용합니닀. 하지만 싀제로는 작업의 복잡도가 닀륌 수 있윌므로, 위에서 얞꞉한 방법듀을 통핎 작업 분배 방식을 볎닀 섞밀하게 조정할 필요가 있습니닀.

작업의 복잡도나 자원 소비량을 고렀하여 작업을 할당하는 것은 멀티슀레딩 프로귞랚의 성능을 최적화하는 데 쀑요한 요소입니닀. 따띌서, 작업의 특성을 정확히 파악하고, 읎에 Ʞ반한 적절한 작업 분배 전략을 선택하는 것읎 쀑요합니닀.

(ì°žê³ ) 귞렇닀멎 얎떻게 멀티슀레딩 프로귞랚의 성능을 최적화륌 할까?

queue륌 사용핎서 task의 복잡도륌 정의하고 읎륌 args로 넣얎죌멎 각 슀레드가 처늬할 데읎터의 양을 명확하게 정의핎쀄 수 있습니닀. (아래 예시윔드 ì°žê³ )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import time
import queue

# 작업 핚수
def worker(work_queue):
    while not work_queue.empty():
        try:
            # 큐에서 작업을 가젞옎
            task = work_queue.get_nowait()
        except queue.Empty:
            break

        # 작업의 낎용(여Ʞ서는 닚순히 음정 시간 대Ʞ하는 것윌로 가정)
        print(f"{threading.current_thread().name} is processing task: {task}")
        time.sleep(task)
        print(f"{threading.current_thread().name} finished task: {task}")

        # 작업 완료륌 큐에 알늌
        work_queue.task_done()

# 작업 큐 생성 및 작업 추가
work_queue = queue.Queue()
tasks = [2, 4, 6, 8, 1, 3, 5, 7]  # 각 숫자는 작업의 "복잡도"륌 나타냄(예: 처늬 시간)
for task in tasks:
    work_queue.put(task)

# 슀레드 생성 및 시작
num_threads = 4
threads = []
for i in range(num_threads):
    t = threading.Thread(target=worker, args=(work_queue,))
    t.start()
    threads.append(t)

# 몚든 슀레드의 작업읎 완료될 때까지 대Ʞ
for t in threads:
    t.join()

print("All tasks are completed.")


-->