비동기 처리의 핵심은 동시성을 제공하면서도 단일 스레드에서 실행된다는 점입니다. 이는 주로 I/O 작업(예: 파일 읽기/쓰기, 네트워크 요청 등)에서 유용합니다. 비동기 처리는 이러한 작업을 기다리는 동안 CPU가 다른 작업을 처리할 수 있도록 해줍니다.
이벤트 루프 (Event Loop):
코루틴 (Coroutines):
async def
로 정의된 함수입니다. 코루틴은 실행 중에 await
키워드를 만나면 실행을 일시 중단하고, 다른 작업이 실행될 수 있도록 제어를 이벤트 루프에 넘깁니다.Futures:
Future
객체는 나중에 완료될 작업의 결과를 포함하며, 이벤트 루프가 해당 작업이 완료되면 결과를 반환합니다.Tasks:
asyncio.Task
는 코루틴을 감싸서 실행을 관리하며, 완료되면 Future
객체로 결과를 반환합니다.이벤트 루프 시작:
asyncio.run()
또는 asyncio.get_event_loop()
를 호출하여 이벤트 루프를 시작합니다.코루틴 실행:
await
키워드를 만나면 실행을 중단하고, 이벤트 루프는 다른 작업을 실행합니다.I/O 작업 대기:
await
를 통해 I/O 작업을 기다리는 동안, 이벤트 루프는 다른 코루틴을 실행합니다. 이로 인해 CPU가 유휴 상태로 남지 않고 다른 작업을 처리할 수 있습니다.작업 완료:
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())
fetch_data
코루틴:
async def
로 정의된 비동기 함수입니다. await asyncio.sleep(2)
는 2초 동안 대기하는 동안 다른 작업이 실행될 수 있도록 합니다.main
코루틴:
fetch_data
코루틴을 호출하고, 그 결과를 기다립니다. await
키워드를 사용하여 fetch_data
가 완료될 때까지 기다립니다.이벤트 루프 실행:
asyncio.run(main())
을 통해 이벤트 루프를 시작하고, main
코루틴을 실행합니다.비동기 처리는 이벤트 루프와 코루틴을 사용하여 I/O 작업을 효율적으로 처리하는 방식입니다. 이를 통해 단일 스레드에서 여러 작업을 동시에 처리할 수 있으며, 특히 I/O 바운드 작업에서 성능을 크게 향상시킬 수 있습니다.
비동기 처리의 핵심은 동시성을 제공하는 것이지만, 이는 병렬 처리와는 다르다는 점을 기억해야 해. 이제 질문에 대한 답을 단계별로 설명할게.
작업 시작과 일시 중단:
await
키워드를 만나면 실행을 일시 중단해. 이때, 해당 작업은 완전히 멈추는 것이 아니라, 다른 작업이 실행될 수 있도록 제어권을 이벤트 루프에 넘기는 것이야.다음 작업 시작:
await
로 인해 일시 중단된 동안, 이벤트 루프는 다른 비동기 작업을 실행해. 이 작업도 마찬가지로 await
를 만나면 일시 중단될 수 있어.await
를 만나면 다시 첫 번째 작업으로 돌아갈 수 있어.작업이 동시에 유지되는가?:
비동기 처리를 이해하기 쉽게 비유해볼게:
이 과정에서 두 작업이 동시에 실행되는 것처럼 보이지만, 실제로는 이벤트 루프가 작업을 번갈아가며 처리하는 거야. 즉, 첫 번째 작업이 멈춘 동안에도 두 번째 작업이 실행되고, 첫 번째 작업은 백그라운드에서 유지되다가 다시 실행될 기회를 얻는 거지.
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())
task1
:
await asyncio.sleep(2)
로 인해 2초 동안 멈추고, 그동안 다른 작업이 실행될 수 있어.task2
:
await asyncio.sleep(1)
로 인해 1초 동안 멈추고, 그동안 다른 작업이 실행될 수 있어.asyncio.gather
:
task1
이 2초 동안 대기하는 동안, task2
는 1초 동안 대기하고, task2
가 끝나면 다시 task1
이 재개돼.