비동기 처리의 작업 과정 원리

minsing-jin·2024년 9월 11일
1

비동기 처리 원리

비동기 처리의 핵심은 동시성을 제공하면서도 단일 스레드에서 실행된다는 점입니다. 이는 주로 I/O 작업(예: 파일 읽기/쓰기, 네트워크 요청 등)에서 유용합니다. 비동기 처리는 이러한 작업을 기다리는 동안 CPU가 다른 작업을 처리할 수 있도록 해줍니다.

주요 개념

  1. 이벤트 루프 (Event Loop):

    • 비동기 처리의 중심입니다. 이벤트 루프는 여러 작업을 관리하고, 각 작업이 완료될 때까지 기다렸다가 다시 실행을 재개합니다.
    • 이벤트 루프는 비동기 함수(코루틴)를 스케줄링하고, I/O 작업이 완료되면 해당 작업을 다시 실행합니다.
  2. 코루틴 (Coroutines):

    • async def로 정의된 함수입니다. 코루틴은 실행 중에 await 키워드를 만나면 실행을 일시 중단하고, 다른 작업이 실행될 수 있도록 제어를 이벤트 루프에 넘깁니다.
    • 코루틴은 비동기 함수로, 동기 함수와 달리 실행을 중단하고 나중에 다시 재개할 수 있습니다.
  3. Futures:

    • 아직 완료되지 않은 작업의 결과를 나타내는 객체입니다. Future 객체는 나중에 완료될 작업의 결과를 포함하며, 이벤트 루프가 해당 작업이 완료되면 결과를 반환합니다.
  4. Tasks:

    • 코루틴을 실행하기 위해 이벤트 루프에 의해 관리되는 객체입니다. asyncio.Task는 코루틴을 감싸서 실행을 관리하며, 완료되면 Future 객체로 결과를 반환합니다.

비동기 처리의 동작 원리

  1. 이벤트 루프 시작:

    • asyncio.run() 또는 asyncio.get_event_loop()를 호출하여 이벤트 루프를 시작합니다.
    • 이벤트 루프는 대기 중인 작업(코루틴)을 관리하고, 각 작업이 완료될 때까지 기다립니다.
  2. 코루틴 실행:

    • 코루틴은 await 키워드를 만나면 실행을 중단하고, 이벤트 루프는 다른 작업을 실행합니다.
    • 예를 들어, 네트워크 요청을 보내고 응답을 기다리는 동안 다른 코루틴이 실행될 수 있습니다.
  3. I/O 작업 대기:

    • 코루틴이 await를 통해 I/O 작업을 기다리는 동안, 이벤트 루프는 다른 코루틴을 실행합니다. 이로 인해 CPU가 유휴 상태로 남지 않고 다른 작업을 처리할 수 있습니다.
  4. 작업 완료:

    • I/O 작업이 완료되면 이벤트 루프는 해당 코루틴을 다시 실행하여 남은 작업을 처리합니다.

예시 코드

import asyncio

async def fetch_data():
    print("데이터 요청 중...")
    await asyncio.sleep(2)  # 네트워크 요청을 시뮬레이션
    print("데이터 수신 완료")
    return "데이터"

async def main():
    print("비동기 작업 시작")
    result = await fetch_data()
    print(f"결과: {result}")

# 이벤트 루프 실행
asyncio.run(main())

코드 설명

  1. fetch_data 코루틴:

    • async def로 정의된 비동기 함수입니다. await asyncio.sleep(2)는 2초 동안 대기하는 동안 다른 작업이 실행될 수 있도록 합니다.
  2. main 코루틴:

    • fetch_data 코루틴을 호출하고, 그 결과를 기다립니다. await 키워드를 사용하여 fetch_data가 완료될 때까지 기다립니다.
  3. 이벤트 루프 실행:

    • asyncio.run(main())을 통해 이벤트 루프를 시작하고, main 코루틴을 실행합니다.

비동기 처리의 장점

  • 효율적인 자원 사용: 비동기 처리는 I/O 작업을 기다리는 동안 CPU가 다른 작업을 처리할 수 있도록 하여 자원을 효율적으로 사용합니다.
  • 동시성: 여러 작업을 동시에 처리할 수 있어, 특히 네트워크 요청이나 파일 입출력과 같은 I/O 바운드 작업에서 성능이 크게 향상됩니다.

결론

비동기 처리는 이벤트 루프코루틴을 사용하여 I/O 작업을 효율적으로 처리하는 방식입니다. 이를 통해 단일 스레드에서 여러 작업을 동시에 처리할 수 있으며, 특히 I/O 바운드 작업에서 성능을 크게 향상시킬 수 있습니다.


비동기 처리의 핵심은 동시성을 제공하는 것이지만, 이는 병렬 처리와는 다르다는 점을 기억해야 해. 이제 질문에 대한 답을 단계별로 설명할게.

비동기 작업의 흐름

  1. 작업 시작과 일시 중단:

    • 비동기 함수(코루틴)는 await 키워드를 만나면 실행을 일시 중단해. 이때, 해당 작업은 완전히 멈추는 것이 아니라, 다른 작업이 실행될 수 있도록 제어권을 이벤트 루프에 넘기는 것이야.
    • 예를 들어, 네트워크 요청을 보내고 응답을 기다리는 동안, CPU는 다른 작업을 처리할 수 있어. 이때, 첫 번째 작업은 네트워크 응답을 기다리며 멈춰있지만, 이벤트 루프는 다른 작업을 실행할 수 있는 상태가 돼.
  2. 다음 작업 시작:

    • 첫 번째 작업이 await로 인해 일시 중단된 동안, 이벤트 루프는 다른 비동기 작업을 실행해. 이 작업도 마찬가지로 await를 만나면 일시 중단될 수 있어.
    • 중요한 점은 첫 번째 작업이 멈춰있는 동안에도 이벤트 루프는 다른 작업을 계속해서 실행한다는 거야. 즉, 첫 번째 작업이 멈춘 상태에서 두 번째 작업이 시작되고, 두 번째 작업이 await를 만나면 다시 첫 번째 작업으로 돌아갈 수 있어.
  3. 작업이 동시에 유지되는가?:

    • 첫 번째 작업이 멈춘 상태에서 두 번째 작업이 시작되지만, 첫 번째 작업은 여전히 이벤트 루프에 의해 관리되고 있어. 즉, 첫 번째 작업이 완전히 종료된 것이 아니라, 일시 중단된 상태로 유지되고 있는 거야.
    • 두 번째 작업이 실행되는 동안, 첫 번째 작업은 백그라운드에서 대기하고 있다가, 다시 실행될 기회가 오면 재개돼.

비유를 통한 설명

비동기 처리를 이해하기 쉽게 비유해볼게:

  • 첫 번째 작업은 네트워크 요청을 보내고 응답을 기다리는 중이라고 생각해보자. 이때, 네트워크 응답이 올 때까지 기다리는 동안 CPU는 할 일이 없어.
  • 두 번째 작업은 파일을 읽는 작업이라고 하자. 첫 번째 작업이 응답을 기다리는 동안, CPU는 두 번째 작업을 처리할 수 있어.
  • 첫 번째 작업이 응답을 기다리는 동안, 두 번째 작업이 실행되고, 두 번째 작업이 끝나면 다시 첫 번째 작업으로 돌아가서 응답을 처리해.

이 과정에서 두 작업이 동시에 실행되는 것처럼 보이지만, 실제로는 이벤트 루프가 작업을 번갈아가며 처리하는 거야. 즉, 첫 번째 작업이 멈춘 동안에도 두 번째 작업이 실행되고, 첫 번째 작업은 백그라운드에서 유지되다가 다시 실행될 기회를 얻는 거지.

코드 예시

import asyncio

async def task1():
    print("Task 1 시작")
    await asyncio.sleep(2)  # 2초 동안 대기 (네트워크 요청 대기 시뮬레이션)
    print("Task 1 완료")

async def task2():
    print("Task 2 시작")
    await asyncio.sleep(1)  # 1초 동안 대기 (파일 읽기 시뮬레이션)
    print("Task 2 완료")

async def main():
    # 두 작업을 동시에 실행
    await asyncio.gather(task1(), task2())

# 이벤트 루프 실행
asyncio.run(main())

코드 설명

  1. task1:

    • 2초 동안 대기하는 작업이야. 이 작업은 await asyncio.sleep(2)로 인해 2초 동안 멈추고, 그동안 다른 작업이 실행될 수 있어.
  2. task2:

    • 1초 동안 대기하는 작업이야. await asyncio.sleep(1)로 인해 1초 동안 멈추고, 그동안 다른 작업이 실행될 수 있어.
  3. asyncio.gather:

    • 두 작업을 동시에 실행해. task1이 2초 동안 대기하는 동안, task2는 1초 동안 대기하고, task2가 끝나면 다시 task1이 재개돼.

결론

  • 첫 번째 작업이 멈춘 동안에도 두 번째 작업은 실행될 수 있어. 하지만 첫 번째 작업은 완전히 종료된 것이 아니라, 일시 중단된 상태로 유지되고 있어.
  • 비동기 처리는 여러 작업을 동시에 실행하는 것처럼 보이지만, 실제로는 이벤트 루프가 작업을 번갈아가며 처리하는 방식이야.
profile
why not? 정신으로 맨땅에 헤딩하고 있는 코린이

0개의 댓글