비동기식 python 함수 처리, 핸들러

개발 오답 노트·2024년 11월 5일

Python

목록 보기
2/2

비동기 프로그래밍은 특정 작업을 수행하는 동안 다른 작업을 동시에 처리할 수 있는 방식입니다. Python에서 asyncio 모듈은 비동기 프로그래밍을 지원하여, 비동기 함수들을 작성하고 실행할 수 있게 합니다. 이 방식의 주요 목적은 효율적인 I/O 작업 처리입니다.

비동기 프로그래밍의 이유

  1. I/O 작업 중 대기 시간 줄이기:
    • 네트워크 요청, 파일 읽기/쓰기, 데이터베이스 쿼리 등 많은 I/O 작업은 대기 시간이 발생합니다. 예를 들어, 파일을 읽는 동안 CPU는 그 파일이 디스크에서 읽혀지기를 기다려야 합니다.
    • 비동기 프로그래밍은 이런 대기 시간 동안 다른 작업을 수행할 수 있게 해줍니다. 즉, I/O 작업이 완료되기를 기다리는 동안 다른 함수가 실행될 수 있어, 자원을 더 효율적으로 사용할 수 있습니다.
  2. 효율적인 자원 사용:
    • 비동기 방식에서는 CPU를 더 효율적으로 사용하며, 특히 많은 I/O 작업을 처리하는 서버 애플리케이션에서 성능을 크게 향상시킬 수 있습니다. 이는 여러 작업이 대기 상태일 때 다른 작업을 처리할 수 있기 때문입니다.

비동기 프로그래밍의 장단점

장점

  1. 동시성:
    • 여러 작업을 동시에 처리하는 것처럼 보이게 합니다. 실제로는 하나의 스레드에서 실행되지만, 비동기 방식으로 여러 I/O 작업을 병렬로 처리할 수 있습니다.
    • 비동기 함수들은 작업 간의 전환이 효율적이어서, 많은 클라이언트의 요청을 동시에 처리해야 하는 웹 서버와 같은 애플리케이션에서 유리합니다.
  2. 스레드/프로세스 오버헤드 감소:
    • 전통적인 멀티스레딩 또는 멀티프로세싱 방식과 달리, 비동기 프로그래밍은 추가적인 스레드 또는 프로세스를 생성하지 않아도 됩니다. 이로 인해 스레드/프로세스 간의 문맥 전환 비용이 줄어들고, 더 적은 자원으로 높은 동시성을 달성할 수 있습니다.
  3. 효율적인 I/O 처리:
    • 비동기 방식으로 I/O를 처리하면, CPU가 I/O 대기 시간 동안 유휴 상태에 머물지 않고 다른 작업을 수행할 수 있습니다.

단점

  1. 복잡성 증가:
    • 비동기 코드는 동기 코드보다 이해하고 디버그하기 어렵습니다. 작업이 비동기적으로 발생하고, 그 작업들이 여러 곳에서 실행될 수 있기 때문에 코드의 흐름을 추적하기 복잡해질 수 있습니다.
  2. 데드락 및 레이스 컨디션:
    • 비동기 코드를 잘못 작성하면, 예상치 못한 데드락(작업이 서로 끝나기를 기다리며 영원히 대기하는 상황)이나 레이스 컨디션(두 개 이상의 작업이 동시에 실행되며 서로 간섭하여 예기치 않은 결과를 초래하는 상황)이 발생할 수 있습니다.
  3. 비동기 라이브러리 의존:
    • 비동기 프로그래밍을 사용할 때는 비동기 방식으로 작동하는 라이브러리를 사용해야 합니다. 모든 라이브러리가 비동기 방식을 지원하는 것은 아니므로, 호환성을 고려해야 합니다.

asyncawait 구문 설명

  • async 키워드:
    • 이 키워드는 함수 정의 앞에 붙여서 해당 함수가 비동기로 작동할 것임을 명시합니다. async로 정의된 함수는 코루틴이 됩니다.

    • 코루틴은 일종의 함수지만, 일반적인 함수와 달리 실행이 중단될 수 있고, 중단된 지점부터 다시 실행할 수 있습니다.

      python코드 복사
      async def my_coroutine():
          # 비동기 작업을 수행하는 코드
          pass
      
  • await 키워드:
    • await는 비동기 함수(또는 코루틴)를 호출할 때 사용합니다. 이 키워드는 비동기 작업이 완료될 때까지 현재 함수의 실행을 일시적으로 중단하고, 비동기 작업이 완료되면 실행을 재개합니다.

    • await비동기 함수 내에서만 사용할 수 있습니다.

      python코드 복사
      async def my_coroutine():
          result = await some_async_function()  # 비동기 함수의 완료를 기다림
          print(result)
      

간단한 예제

python코드 복사
import asyncio

async def fetch_data():
    print("Start fetching data...")
    await asyncio.sleep(2)  # 2초간 대기 (I/O 작업을 시뮬레이션)
    print("Data fetched!")
    return {"data": "sample"}

async def main():
    print("Before fetching data")
    data = await fetch_data()
    print("After fetching data:", data)

asyncio.run(main())

코드 설명

  1. fetch_data 함수:
    • async로 정의된 비동기 함수입니다. 이 함수는 2초간 대기(await asyncio.sleep(2))한 후 데이터를 반환합니다.
    • await asyncio.sleep(2)는 2초간 대기하는 동안 다른 작업이 실행될 수 있도록 CPU 제어를 양보합니다.
  2. main 함수:
    • main 함수에서도 비동기 함수인 fetch_data를 호출하기 위해 await를 사용합니다.
    • asyncio.run(main())는 이벤트 루프를 실행하고, main 함수가 종료될 때까지 대기합니다.

결론

비동기 프로그래밍은 특히 I/O 중심 작업에서 효율성을 극대화할 수 있습니다. asyncio 모듈과 async, await 키워드를 사용하면 Python에서 이러한 비동기 작업을 쉽게 구현할 수 있습니다. 하지만, 비동기 코드는 복잡성이 증가할 수 있으므로 필요에 따라 신중하게 사용하는 것이 중요합니다.

비동기 함수와 핸들러의 역할

비동기 프로그래밍에서는 작업이 실행되기를 기다리기보다는, 작업이 완료될 때까지 다른 작업을 계속 실행할 수 있습니다. 이렇게 하면 프로그램의 효율성이 크게 향상됩니다.

1. 비동기 함수 (async function)

  • async def로 정의된 함수는 비동기 함수입니다.
  • 이 함수는 호출 시 작업을 바로 실행하지 않고, 비동기적으로 실행할 수 있도록 준비만 해둡니다.
  • 비동기 함수는 await 키워드로 다른 비동기 작업을 기다립니다.
python코드 복사
async def my_async_function():
    await some_other_async_function()

2. 핸들러 (Handler)

  • 비동기 함수의 결과를 처리하는 데 사용되는 함수입니다.
  • 예를 들어, 비동기 작업이 완료되면 호출되는 콜백 함수가 핸들러 역할을 할 수 있습니다.
  • 핸들러는 비동기 작업의 성공, 실패, 또는 특정 이벤트가 발생했을 때 실행됩니다.
python코드 복사
async def process_data():
    data = await fetch_data()
    handle_data(data)

def handle_data(data):
    # 데이터를 처리하는 코드

위 코드에서 handle_data 함수는 process_data 비동기 함수 내에서 비동기 작업이 완료된 후 호출되는 핸들러의 역할을 합니다.

비동기 핸들러의 실사용 예

비동기 프로그래밍에서 핸들러는 다음과 같은 상황에서 주로 사용됩니다:

  • I/O 작업 (파일 읽기/쓰기, 네트워크 요청 등): 작업이 완료되면 결과를 처리하거나 오류를 처리하기 위해 핸들러가 호출됩니다.
  • 이벤트 기반 시스템: 특정 이벤트가 발생했을 때, 해당 이벤트에 대한 처리를 수행하기 위해 핸들러가 사용됩니다.

Python에서의 예제

python코드 복사
import asyncio

async def download_file(url):
    print(f"Downloading from {url}")
    await asyncio.sleep(2)  # 파일 다운로드 시뮬레이션
    return "file_content"

async def save_file(content):
    print("Saving file...")
    await asyncio.sleep(1)  # 파일 저장 시뮬레이션
    print(f"File saved with content: {content}")

async def main():
    file_content = await download_file("http://example.com")
    await save_file(file_content)

asyncio.run(main())

이 예제에서 download_filesave_file은 비동기 함수이며, main 함수는 비동기 작업이 완료될 때 이를 처리하는 핸들러 역할을 합니다. 이 방식으로 비동기 작업의 결과를 처리할 수 있습니다.

핸들러는 주로 비동기 작업의 결과를 처리하거나, 에러가 발생했을 때 이를 처리하기 위해 사용되며, 비동기 프로그래밍의 핵심 구성 요소입니다.

profile
포토폴리오 https://wikidocs.net/book/10969 유튜브 링크 https://www.youtube.com/@%EC%B5%9C%EC%9B%90%EC%9D%BC-n5r

0개의 댓글