프로그래밍백엔드 개발자

파이썬에서 async/await를 사용한 비동기 프로그래밍의 구현 방식을 설명하십시오. 이 접근 방식의 장점과 어려움은 무엇입니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

비동기 프로그래밍은 파이썬 3.5 버전부터 asyncawait 키워드 도입으로 시작되었습니다. 처음에는 비동기 작업에 asyncio와 코루틴 기반 생성기와 같은 라이브러리를 사용했으며, 이는 이해하고 유지하기 어려웠습니다. async/await 문법의 등장으로 비동기 코드는 더욱 명확하고 읽기 쉬워졌으며, 익숙한 동기 스타일에 가까워졌습니다.

역사적 측면

async/await 이전에는 비동기성이 콜백 및 생성기를 통해 구현되었습니다(예: tornado 라이브러리나 오래된 asyncio API를 사용). 이러한 코드는 디버깅 및 유지 관리가 어려웠습니다.

문제

동기 코드에서 많은 동시 I/O 작업(네트워크 요청, 파일 입출력)을 처리할 때의 주요 문제는 주요 스레드가 차단되는 것입니다. 이는 성능 저하와 자원을 효율적으로 사용할 수 없는 문제를 일으킵니다.

해결책

async/await를 사용한 비동기 프로그래밍은 하나의 스레드 내에서 많은 입출력 작업을 병렬로 수행할 수 있게 하며, 차단을 피할 수 있습니다. 이때 문법은 일반 함수와 비슷해 읽기 쉽고 디버깅하기 쉬워집니다.

코드 예시:

import asyncio async def fetch_data(delay): print(f"{delay}초 지연 후 데이터 가져오기 시작") await asyncio.sleep(delay) print(f"{delay}초 지연 후 데이터 가져오기 완료") return delay async def main(): results = await asyncio.gather( fetch_data(1), fetch_data(2), fetch_data(3) ) print("결과:", results) asyncio.run(main())

주요 특징:

  • 스레드 차단 없음: 입출력 작업이 스레드를 해방시킵니다.
  • 비동기 호출을 위한 명확한 문법(async/await).
  • asyncio를 지원하는 라이브러리와의 쉬운 통합.

함정 질문들.

async def로 정의된 함수는 일반 함수처럼 호출될 수 있습니까?

아니오. 이러한 함수를 호출하면 코루틴 객체가 반환되며, 이는 이벤트 루프에 전달되기 전까지 실행되지 않습니다(예: await 또는 asyncio.run()을 통해).

def foo(): return 42 async def bar(): return 42 print(foo()) # 42 print(bar()) # <coroutine object bar at ...>

비동기 함수 밖에서 await를 사용할 수 있습니까?

아니오. await 키워드는 반드시 async def로 선언된 함수 내에서만 사용되어야 합니다. 이러한 함수 외부에서 await를 사용하면 SyntaxError가 발생합니다.

# 오류! await asyncio.sleep(1) # SyntaxError: 'await' outside async function

I/O와 관련 없는 작업(예: 계산)에 비동기성이 적용됩니까?

아니오. 비동기성은 입력 및 출력 작업에만 효과적입니다. 계산 작업에는 여전히 multiprocessing이나 threading이 필요하며, 그렇지 않으면 이벤트 루프가 차단됩니다.

전형적인 오류 및 안티패턴

장점:

  • I/O 작업의 대기 시간을 상당히 줄입니다.
  • 서버와 애플리케이션의 응답성을 높입니다.
  • 멀티스레딩 문제를 피하면서 단일 스레드 특성을 유지합니다.

단점:

  • 비동기 코드는 테스트하기 어렵습니다.
  • 모든 라이브러리가 asyncio를 지원하는 것은 아닙니다.
  • 비동기성이 계산 속도를 나아지게 한다는 잘못된 믿음 — 이는 I/O에만 해당됩니다.

실제 예시

부정적인 사례: 젊은 개발자들이 async/await를 사용하여 애플리케이션을 가속화하려 했지만, 비동기적으로 계산만 하고 네트워크 요청이 없었습니다. 애플리케이션은 속도가 빠르지 않았습니다. 장점: 문법에 익숙해짐. 단점: 이득 없음, 코드가 복잡해짐.

긍정적인 사례: 수천 개의 API 요청을 비동기적으로 처리했습니다. 서버는 리소스 증가 없이 더 많은 클라이언트를 처리할 수 있었습니다. 장점: 성능이 크게 향상되었고, 아키텍처도 더 간단해졌습니다. 단점: 신입 개발자에게 진입 장벽이 높아졌습니다.