본문 바로가기

Python

Python asyncio 완벽 입문 - 비동기 프로그래밍으로 성능 10배 높이기

{ } Python Python asyncio 비동기 프로그래밍 입문 async / await

Python asyncio 완벽 입문 - 비동기 프로그래밍으로 성능 10배 높이기

여러 API를 동시에 호출하거나 대량의 파일을 처리할 때 순차적으로 처리하면 너무 느리죠. Python asyncio는 이런 I/O 작업을 동시에 처리해서 성능을 획기적으로 개선할 수 있는 비동기 프로그래밍 프레임워크예요.

asyncio가 필요한 이유

일반적인 동기 코드는 한 작업이 끝나야 다음 작업을 시작해요. 예를 들어 3개의 API를 각각 1초씩 호출하면 총 3초가 걸리죠. 하지만 asyncio를 사용하면 세 요청을 동시에 보내서 약 1초 만에 완료할 수 있어요.

asyncio는 멀티스레딩보다 가볍고, GIL(Global Interpreter Lock) 문제에서 자유로워요. 특히 네트워크 요청, 파일 I/O, 데이터베이스 쿼리 같은 I/O 바운드 작업에서 진가를 발휘하죠.

async/await 기본 문법

비동기 함수는 async def로 정의하고, 비동기 함수를 호출할 때는 await 키워드를 사용해요.

import asyncio

async def fetch_data(n):
    print(f"작업 {n} 시작")
    await asyncio.sleep(1)  # 비동기 대기
    print(f"작업 {n} 완료")
    return f"결과 {n}"

async def main():
    result = await fetch_data(1)
    print(result)

asyncio.run(main())

asyncio.sleep()은 일반 time.sleep()과 달리 다른 작업이 실행될 수 있도록 제어권을 양보해요. asyncio.run()은 비동기 함수를 실행하는 진입점이에요.

여러 작업 동시 실행하기

진짜 위력은 여러 작업을 동시에 실행할 때 나타나요. asyncio.gather()asyncio.create_task()를 사용하면 돼요.

async def main():
    # 3개 작업을 동시에 실행
    results = await asyncio.gather(
        fetch_data(1),
        fetch_data(2),
        fetch_data(3)
    )
    print(results)  # ['결과 1', '결과 2', '결과 3']

순차 실행이면 3초 걸릴 작업이 약 1초 만에 완료돼요. gather()는 모든 작업이 완료될 때까지 기다리고 결과를 리스트로 반환해요.

실전 활용 - HTTP 요청 동시 처리

실무에서 가장 많이 사용하는 패턴은 여러 API를 동시에 호출하는 거예요. aiohttp 라이브러리와 함께 사용하면 강력하죠.

import aiohttp

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

async def main():
    urls = ['https://api1.com', 'https://api2.com']
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)

세션을 재사용하고 연결을 효율적으로 관리해서 성능이 더욱 향상돼요.

주의사항

CPU 집약적 작업에는 비효율적이에요. asyncio는 I/O 대기 시간에 다른 작업을 처리하는 방식이라, 복잡한 계산 작업에는 멀티프로세싱이 더 적합해요. 또한 await 없이 비동기 함수를 호출하면 코루틴 객체만 반환되고 실행되지 않으니 주의하세요.

결론

Python asyncio는 I/O 작업이 많은 애플리케이션에서 성능을 극적으로 개선할 수 있는 도구예요. async/await 문법은 생각보다 간단하고, asyncio.gather()로 동시 실행도 쉽게 구현할 수 있죠. API 호출, 웹 스크래핑, 실시간 데이터 처리 등 다양한 상황에서 활용해보세요!