본문 바로가기
Python 문법/Python 기본 문법(3.10 기준)

[python3.10 기본] 20. 병행성 및 병렬성

by cogito21_python 2024. 7. 2.
반응형

20.1 threading 모듈

threading 모듈은 스레드를 사용한 병행성을 지원합니다. 이를 통해 여러 작업을 동시에 수행할 수 있습니다.

 

기본 사용법

import threading
import time

def print_numbers():
    for i in range(10):
        print(i)
        time.sleep(0.5)

def print_letters():
    for letter in "abcdefghij":
        print(letter)
        time.sleep(0.5)

t1 = threading.Thread(target=print_numbers)
t2 = threading.Thread(target=print_letters)

t1.start()
t2.start()

t1.join()
t2.join()

스레드 클래스

import threading
import time

class PrintNumbers(threading.Thread):
    def run(self):
        for i in range(10):
            print(i)
            time.sleep(0.5)

class PrintLetters(threading.Thread):
    def run(self):
        for letter in "abcdefghij":
            print(letter)
            time.sleep(0.5)

t1 = PrintNumbers()
t2 = PrintLetters()

t1.start()
t2.start()

t1.join()
t2.join()

20.2 multiprocessing 모듈

multiprocessing 모듈은 프로세스를 사용한 병렬성을 지원합니다. 이를 통해 여러 작업을 병렬로 수행할 수 있습니다.

 

기본 사용법

from multiprocessing import Process
import os

def print_process_info(name):
    print(f"Process {name}: {os.getpid()}")

if __name__ == '__main__':
    p1 = Process(target=print_process_info, args=('p1',))
    p2 = Process(target=print_process_info, args=('p2',))

    p1.start()
    p2.start()

    p1.join()
    p2.join()

프로세스 클래스

from multiprocessing import Process

class PrintProcessInfo(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f"Process {self.name}: {os.getpid()}")

if __name__ == '__main__':
    p1 = PrintProcessInfo('p1')
    p2 = PrintProcessInfo('p2')

    p1.start()
    p2.start()

    p1.join()
    p2.join()

20.3 concurrent.futures 모듈

concurrent.futures 모듈은 병행 및 병렬 작업을 쉽게 관리할 수 있는 고수준 인터페이스를 제공합니다.

 

ThreadPoolExecutor 사용

from concurrent.futures import ThreadPoolExecutor

def print_number(number):
    print(number)

with ThreadPoolExecutor(max_workers=5) as executor:
    numbers = range(10)
    executor.map(print_number, numbers)

ProcessPoolExecutor 사용

from concurrent.futures import ProcessPoolExecutor

def square(number):
    return number * number

with ProcessPoolExecutor(max_workers=5) as executor:
    numbers = range(10)
    results = executor.map(square, numbers)
    for result in results:
        print(result)

20.4 비동기 프로그래밍의 패턴과 사용 사례

비동기 프로그래밍은 asyncio 모듈을 사용하여 비동기 작업을 쉽게 관리할 수 있습니다.

 

asyncio 기본 사용법

import asyncio

async def say_hello():
    print("Hello")
    await asyncio.sleep(1)
  	print("World")

  async def main():
      await say_hello()

  asyncio.run(main())

 

비동기 작업 병행 실행

import asyncio

async def task1():
    print("Task 1 start")
    await asyncio.sleep(2)
    print("Task 1 end")

async def task2():
    print("Task 2 start")
    await asyncio.sleep(1)
    print("Task 2 end")

async def main():
    await asyncio.gather(task1(), task2())

asyncio.run(main())

비동기 작업과 HTTP 요청 처리 (aiohttp 사용)

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        urls = [
            "http://example.com",
            "http://example.org",
            "http://example.net"
        ]
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        for result in results:
            print(result[:100])  # 첫 100글자만 출력

asyncio.run(main())

병행성 및 병렬성의 차이점

  • 병행성: 여러 작업이 동일한 시간 간격 내에서 번갈아가며 실행됩니다. 일반적으로 단일 CPU 코어에서 여러 작업을 번갈아가며 실행하는 방식입니다.
  • 병렬성: 여러 작업이 동일한 시간에 동시에 실행됩니다. 여러 CPU 코어를 사용하여 각 작업을 병렬로 실행하는 방식입니다.

예제

다음은 threading, multiprocessing, concurrent.futures, asyncio를 사용한 병행성과 병렬성의 예제입니다.

 

threading 예제

import threading
import time

def worker(num):
    print(f"Worker {num} start")
    time.sleep(1)
    print(f"Worker {num} end")

threads = []
for i in range(5):
    t = threading.Thread(target=worker, args=(i,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

multiprocessing 예제

from multiprocessing import Process

def worker(num):
    print(f"Worker {num} start")
    time.sleep(1)
    print(f"Worker {num} end")

processes = []
for i in range(5):
    p = Process(target=worker, args=(i,))
    processes.append(p)
    p.start()

for p in processes:
    p.join()

concurrent.futures 예제

from concurrent.futures import ThreadPoolExecutor
import time

def worker(num):
    print(f"Worker {num} start")
    time.sleep(1)
    print(f"Worker {num} end")

with ThreadPoolExecutor(max_workers=5) as executor:
    executor.map(worker, range(5))

asyncio 예제

import asyncio

async def worker(num):
    print(f"Worker {num} start")
    await asyncio.sleep(1)
    print(f"Worker {num} end")

async def main():
    await asyncio.gather(*(worker(i) for i in range(5)))

asyncio.run(main())
반응형