상세 컨텐츠

본문 제목

코루틴(Coroutine)과 비동기 프로그래밍

카테고리 없음

by AI Engineer crystal 2024. 10. 25. 11:42

본문

코루틴(Coroutine)

- 실행을 일시 중단하고 재개할 수 있는 특수한 함수

- 네트워크 요청이나 파일 입출력 같은 I/O 바운드 작업에서 사용

- CPU가 불필요하게 대기하지 않도록, 코루틴을 사용하여 작업을 잠시 중단한 후 다른 작업을 처리 가능

def coroutine_example():
    print("Coroutine initialized")  # 코루틴 초기화 메시지
    x = yield  # 첫 번째 yield, 여기서 멈춤
    print(f"Received value: x = {x}")  # x가 들어오면 출력
    y = yield x + 10  # 두 번째 yield, x + 10을 반환
    print(f"Received another value: y = {y}")  # y가 들어오면 출력
    yield x + y  # x와 y의 합을 반환

# 코루틴을 생성하고 초기화
coro = coroutine_example()
next(coro)  # "Coroutine initialized" 출력

# 첫 번째 값 전송
result1 = coro.send(5)  # 5가 x에 할당
print(result1)  # 출력: 15 (x + 10의 결과)

# 두 번째 값 전송
result2 = coro.send(20)  # 20이 y에 할당
print(result2)  # 출력: 25 (x + y의 결과)
Coroutine initialized
Received value: x = 5
15
Received another value: y = 20
25

 

"yield"이 외부에서 값을 받아들이고 중간에 멈춰서, 다시 실행될 수 있는 역할을 하는 함수여서 yield 에서 대기했다가 send()로 값 전송했을 때 그 값이 x에 할당됩니다.



Python에서는

  • async def: 비동기 함수를 정의할 때 사용됩니다. 이 함수는 일반 함수처럼 즉시 실행되지 않고, 호출될 때 코루틴 객체를 반환합니다.
    • asyncio.create_task()는 비동기 작업을 Task 객체로 만들어 백그라운드에서 바로 실행하는 방식입니다. Task 객체는 비동기 작업의 상태를 추적하거나 작업을 취소(cancel)할 수 있도록 도와줍니다.
      • 이벤트 루프가 이를 관리하게 됩니다.
      • Task는 완료될 때까지 비동기적으로 진행되며, 완료되면 결과를 반환합니다.
    • aiohttp비동기 HTTP 요청을 처리할 수 있는 라이브러리입니다. 여러 네트워크 요청을 동시에 처리할 때 유용합니다. 특히 많은 URL에서 데이터를 가져올 때 비동기 처리를 통해 I/O 바운드 작업을 최적화할 수 있습니다.
      • aiohttp.ClientSession(): 네트워크 요청을 보낼 때 세션을 사용하여 요청을 관리
      • session.get(url): 특정 URL로 GET 요청을 보냅니다.
      • async with: 비동기 컨텍스트 관리자를 사용하여, 네트워크 요청 후 리소스가 자동으로 해제되도록 보장
  • await: 비동기 함수 내에서 다른 비동기 작업을 호출할 때 사용됩니다. 이 키워드는 해당 작업이 완료될 때까지 일시 중단하고, 작업이 끝나면 재개합니다.
import asyncio

async def task1():
    await asyncio.sleep(2)
    print("Task 1 완료")
    return "Task 1 결과"

async def task2():
    await asyncio.sleep(1)
    print("Task 2 완료")
    return "Task 2 결과"

async def main():
    # create_task()로 개별 Task 생성 및 실행
    task1_obj = asyncio.create_task(task1())
    task2_obj = asyncio.create_task(task2())

    # 여러 Task를 gather()로 동시에 실행하고, 결과를 받음
    results = await asyncio.gather(task1_obj, task2_obj)
    print(results)  # ['Task 1 결과', 'Task 2 결과'] 출력

asyncio.run(main())  # 주피터 노트북에서는 asyncio.run() 대신 await 사용
Task 2 완료
Task 1 완료
['Task 1 결과', 'Task 2 결과']

 

두 개의 작업을 동시에 실행하기 때문에 총 2초 안에 모든 작업이 완료됩니다.

import aiohttp
import asyncio

# 여러 URL에서 데이터를 비동기적으로 가져오는 함수
async def fetch(session, url):
    # 네트워크 요청을 보내고 응답 객체를 관리
    async with session.get(url) as response:
        return await response.text()  # 응답 데이터를 텍스트로 반환

# 메인 비동기 함수
async def main():
    # 동시에 요청을 보낼 URL 목록
    urls = ["http://abc.com", "http://def.org", "http://ghi.com"]

    # aiohttp.ClientSession()을 사용해 네트워크 세션을 생성
    async with aiohttp.ClientSession() as session:
        # 각 URL에 대해 비동기적으로 데이터를 가져오는 작업을 생성
        tasks = [fetch(session, url) for url in urls]

        # 모든 비동기 작업을 동시에 실행하고, 결과가 모두 완료될 때까지 대기
        results = await asyncio.gather(*tasks)

        # 각 요청의 응답 데이터를 출력
        for result in results:
            print(result)

# 이벤트 루프를 실행하여 비동기 작업을 처리
asyncio.run(main())