본문 바로가기
E | ngineering

파이똔 asyncio

by 덞웖이 2025. 2. 24.
지난 포스트에서 다룬 내용에 이어서 잠깐 덧붙이자면,
asyncio는 그냥 io와 다르게 앞에 있는 친구를 기다리지 않는다.
나만 몰랐음.

댕댕이 소리는 그만하구 본론으로 드가자...
Python의 asyncio 패키지를 사용하면서
async def은 자주 사용하지만,
async for와 async with는 잘 안보임(내가 몰랐던거임 ^^).

그럼 일단 써보는거임 ...

 


aync for의 심오한 세계

테스트: 비동기 데이터 스트림 시뮬레이션

API에서 데이터를 스트리밍하거나 실시간 로그를 처리한다고 가정하면, 모든 데이터를 한 번에 가져오는 대신, 배치로 받게 됨. 여기에 에이쒸-ㅇ크를 적용해보자.
import asyncio

# 제목은 거창했지만 스트링만 주고받을거임
async def promises_promises():
    for i in range(5):
        await asyncio.sleep(1)
        # yield를 사용하면 메소드 타입이 async_generator가 된다
        yield f"Batch {i}"

async def main_crap():
    async for batch in promises_promises():
        print(f"Received: {batch}")

# asyncio.run(main_crap()) -> 쥬피타 노트북에서는 이미 async 루프가 돌고 있기 때문에 사용할 수 없다고 한다.
await main_crap()
main_crap()이 resolution을 기다림 👉 async for에서 promises_promises() 호출 👉
asyncio.sleep(1) 이 1초 후 resolve 됨 👉 Batch {i} 반환, main_crap()의 루프에서 처리 👉
print문 출력 👉 반봅

다시 정리해보면, 

i Promise Resolve
0 await asyncio.sleep(1) "Batch 0"
1 await asyncio.sleep(1) "Batch 1"
2 await asyncio.sleep(1) "Batch 2"
3 await asyncio.sleep(1) "Batch 3"
4 await asyncio.sleep(1) "Batch 4"

이렇게 1초마다 순차적으로 출력됨

Received: Batch 0

Received: Batch 1

Received: Batch 2

Received: Batch 3

Received: Batch 4

 

다른 방법으로는 Custom Iterator를 만들어서 __next__() 대신 __anext()사용해서 구현을 할 수 있는데 복잡함. (어차피 await를 사용해야함)😫

그럼 어디에 쓸까?

데이터베이스 커서, 스트림, 웹프레임워크에 사용됨... 어ㅇㅇ어다음 주제 데에타베에스 커서 조아... ... 누가 써줄사람 읍나


async with으로 비동기 리소스 관리

import aiofiles

async def write_file():
    async with aiofiles.open("test.txt", mode="w") as f:
        await f.write("dog honey")
async def read_file():
    async with aiofiles.open("test.txt", mode="r") as f:
        content = await f.read()
        print(content)
일반 I/O는 이벤트 루프를 차단하기 때문에 aiofiles를 사용함. 아래처럼 실행하면 silent 하게 실패하는 것 확인.(파일 생성이 안 됨)
async def write_file_io():
    try:
        async with open("test_io.txt", mode="w") as f:
            await f.write("dog honey")
    except Exception:
        print("error")
예외가 발생해도 파일이 안전하게 닫히기때문에 데에타베에스 커넥션, 소켓 처리 등의 비동기 리소스를 다룰 때 리소스 누수 방지를 위해 활용된다구 한다구 한다.

컨텍스트 매니저

데에타베에스 커넥션 풀같은 것이 어떻게 관리되는지 봐봐보보보자
class ConnectionResource:
 # with 블럭에 들어갈 때 자동으루 호출된다
    async def __aenter__(self):
        print("🙋‍♂️ 연결 중...")
        await asyncio.sleep(1)
        print("✅ 연결 완료!")
        return self

 # with블럭을 떠날 때 자동으로 호출된다.
    # object 클래스 오버라이드
    async def __aexit__(self, exc_type, exc, tb):
        print("👋 연결 종료 중...")
        await asyncio.sleep(1)
        print("✅ 연결 종료 완료!")

async def use_resource():
    async with ConnectionResource():
        print("🔁 리소스 사용 중...")
        await asyncio.sleep(2)

 

 

 

신호등 생각나네

 


정리해보자면

기능 사용 예시
async for 비동기 데이터 소스(API, 로그, 스트림)을 반복 처리
async with 비동기 리소스 관리(파일, DB연결, 소켓)
async for와 async with를 활용해서 Python의 비동기 프로그래밍을 더욱 가독성 높고 구조적으로 만들 수 있었음. (뭐 했다고...)
실시간 데이터, 파일 I/O, 네트워크 연결을 다룰 때 중요한 개념들인듯인듯인듯
👋

'E | ngineering' 카테고리의 다른 글

B쁠러쓰마이나쓰Tree  (0) 2025.03.05
데이터베이스 커서와 컬럼형 데이터베이스  (0) 2025.02.26
Threading & Multiprocessing  (0) 2025.02.20
WordCloud 활용  (0) 2024.10.05
Seaborn 활용 2  (0) 2024.10.04