KR_Coroutine - somaz94/python-study GitHub Wiki

Python ์ฝ”๋ฃจํ‹ด ๊ฐœ๋… ์ •๋ฆฌ


1๏ธโƒฃ ์ฝ”๋ฃจํ‹ด ๊ธฐ์ดˆ

์ฝ”๋ฃจํ‹ด์€ ์ง„์ž…์ ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ธ ์„œ๋ธŒ๋ฃจํ‹ด์œผ๋กœ, ์‹คํ–‰์„ ์ผ์‹œ ์ค‘๋‹จํ•˜๊ณ  ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ๋‹ค.

async def simple_coroutine():
    print('์ฝ”๋ฃจํ‹ด ์‹œ์ž‘')
    await asyncio.sleep(1)
    print('์ฝ”๋ฃจํ‹ด ์ข…๋ฃŒ')

# ์‹คํ–‰
import asyncio
asyncio.run(simple_coroutine())

โœ… ํŠน์ง•:

  • ๋น„๋™๊ธฐ ์‹คํ–‰
  • ์‹คํ–‰ ์ค‘๋‹จ/์žฌ๊ฐœ
  • ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ธฐ๋ฐ˜
  • ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์„ฑ ๊ตฌํ˜„
  • ํšจ์œจ์ ์ธ I/O ์ฒ˜๋ฆฌ

์ฝ”๋ฃจํ‹ด ์‹คํ–‰ ๋ฐฉ๋ฒ•:

# ๋ฉ”์ธ ํ•จ์ˆ˜์—์„œ ์‹คํ–‰
async def main():
    await simple_coroutine()
    
asyncio.run(main())

# ์ด๋ฒคํŠธ ๋ฃจํ”„ ์ง์ ‘ ์ œ์–ด
loop = asyncio.get_event_loop()
loop.run_until_complete(simple_coroutine())
loop.close()

# ํƒœ์Šคํฌ๋กœ ์˜ˆ์•ฝ
async def run_tasks():
    task = asyncio.create_task(simple_coroutine())
    await task
    
asyncio.run(run_tasks())


2๏ธโƒฃ yield from๊ณผ async/await

Python์˜ ์ฝ”๋ฃจํ‹ด ๋ฌธ๋ฒ• ์ง„ํ™”์™€ ํ˜„๋Œ€์ ์ธ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด๋‹ค.

# ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ฝ”๋ฃจํ‹ด (์ด์ „ ๋ฐฉ์‹)
def old_style_coroutine():
    yield 'First'
    yield 'Second'
    yield 'Third'

# ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ฝ”๋ฃจํ‹ด ์ฒด์ด๋‹ (Python 3.3+)
def delegator():
    yield from old_style_coroutine()
    
# ํ˜„๋Œ€์ ์ธ ์ฝ”๋ฃจํ‹ด (Python 3.5+)
async def modern_coroutine():
    await asyncio.sleep(1)
    return 'Result'

# ์ฝ”๋ฃจํ‹ด ์ฒด์ด๋‹
async def chain_coroutines():
    first = await modern_coroutine()
    second = await modern_coroutine()
    return [first, second]

โœ… ํŠน์ง•:

  • ํ˜„๋Œ€์  ๋ฌธ๋ฒ• ์ง€์›
  • ์ฝ”๋ฃจํ‹ด ์ฒด์ด๋‹
  • ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
  • ํƒ€์ž… ํžŒํŒ… ์ง€์›
  • ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž ํ˜ธํ™˜

async/await์™€ ์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ๊ด€๊ณ„:

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def concurrent_example():
    start = time.time()
    
    # ๋ณ‘๋ ฌ ์‹คํ–‰
    task1 = asyncio.create_task(say_after(1, '์ž‘์—… 1 ์™„๋ฃŒ'))
    task2 = asyncio.create_task(say_after(2, '์ž‘์—… 2 ์™„๋ฃŒ'))
    
    print(f"์‹œ์ž‘ ์‹œ๊ฐ„: {time.strftime('%X')}")
    
    # ๋‘ ํƒœ์Šคํฌ ์™„๋ฃŒ ๋Œ€๊ธฐ
    await task1
    await task2
    
    end = time.time()
    print(f"๋๋‚œ ์‹œ๊ฐ„: {time.strftime('%X')}")
    print(f"์ด ์†Œ์š” ์‹œ๊ฐ„: {end - start:.2f} ์ดˆ")  # ์•ฝ 2์ดˆ ์†Œ์š” (๋ณ‘๋ ฌ ์‹คํ–‰)

asyncio.run(concurrent_example())


3๏ธโƒฃ ์ฝ”๋ฃจํ‹ด ์ƒํƒœ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์ฝ”๋ฃจํ‹ด์˜ ๋‹ค์–‘ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์ด๋‹ค.

async def error_handling():
    try:
        await risky_operation()
    except Exception as e:
        print(f'์—๋Ÿฌ ๋ฐœ์ƒ: {e}')
    else:
        print('์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ')
    finally:
        print('์ •๋ฆฌ ์ž‘์—… ์ˆ˜ํ–‰')

async def risky_operation():
    await asyncio.sleep(1)
    raise ValueError('์˜๋„์ ์ธ ์—๋Ÿฌ')
    
# ์—ฌ๋Ÿฌ ์˜ˆ์™ธ ์œ ํ˜• ์ฒ˜๋ฆฌ
async def comprehensive_error_handling():
    try:
        await risky_operation()
    except ValueError as e:
        print(f'๊ฐ’ ์˜ค๋ฅ˜: {e}')
    except asyncio.TimeoutError:
        print('์‹œ๊ฐ„ ์ดˆ๊ณผ')
    except asyncio.CancelledError:
        print('์ž‘์—… ์ทจ์†Œ๋จ')
        raise  # ์ทจ์†Œ ์˜ˆ์™ธ๋Š” ๋‹ค์‹œ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์ข‹๋‹ค
    except Exception as e:
        print(f'๊ธฐํƒ€ ์˜ˆ์™ธ: {e}')

โœ… ํŠน์ง•:

  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํŒจํ„ด
  • ์ •๋ฆฌ ์ž‘์—… ๋ณด์žฅ
  • ์ƒํƒœ ๊ด€๋ฆฌ
  • ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์œ ํ˜• ๋Œ€์‘
  • ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž ํ™œ์šฉ

์ƒํƒœ ์ถ”์ ๊ณผ ๋กœ๊น…:

import logging
import contextlib
import time

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

@contextlib.asynccontextmanager
async def track_coroutine_status(name):
    """์ฝ”๋ฃจํ‹ด ์‹คํ–‰ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž"""
    start_time = time.time()
    logging.info(f"์ฝ”๋ฃจํ‹ด '{name}' ์‹œ์ž‘")
    try:
        yield
    except Exception as e:
        logging.error(f"์ฝ”๋ฃจํ‹ด '{name}' ์‹คํ–‰ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
        raise
    finally:
        elapsed = time.time() - start_time
        logging.info(f"์ฝ”๋ฃจํ‹ด '{name}' ์™„๋ฃŒ (์†Œ์š” ์‹œ๊ฐ„: {elapsed:.2f}์ดˆ)")

async def monitored_task():
    async with track_coroutine_status("๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ"):
        await asyncio.sleep(1)  # ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        # raise ValueError("์˜ˆ์‹œ ์˜ค๋ฅ˜")  # ์ฃผ์„ ํ•ด์ œํ•˜์—ฌ ์˜ค๋ฅ˜ ํ…Œ์ŠคํŠธ
        await asyncio.sleep(0.5)  # ์ถ”๊ฐ€ ์ž‘์—…
        return "์ฒ˜๋ฆฌ ์™„๋ฃŒ"


4๏ธโƒฃ ์ฝ”๋ฃจํ‹ด ์กฐํ•ฉํ•˜๊ธฐ

๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•˜๊ณ  ์กฐํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

async def operation1():
    await asyncio.sleep(1)
    return "๊ฒฐ๊ณผ 1"

async def operation2():
    await asyncio.sleep(2)
    return "๊ฒฐ๊ณผ 2"

async def operation3():
    await asyncio.sleep(1.5)
    return "๊ฒฐ๊ณผ 3"

async def parallel_operations():
    # ์—ฌ๋Ÿฌ ์ฝ”๋ฃจํ‹ด ๋™์‹œ ์‹คํ–‰
    results = await asyncio.gather(
        operation1(),
        operation2(),
        operation3()
    )
    return results  # ['๊ฒฐ๊ณผ 1', '๊ฒฐ๊ณผ 2', '๊ฒฐ๊ณผ 3']

async def sequential_operations():
    # ์ˆœ์ฐจ์  ์‹คํ–‰
    result1 = await operation1()
    result2 = await operation2()
    result3 = await operation3()
    return [result1, result2, result3]

# ํŠน์ • ์ˆœ์„œ๋กœ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
async def process_as_completed():
    tasks = [
        operation1(),
        operation2(),
        operation3()
    ]
    
    for coro in asyncio.as_completed(tasks):
        result = await coro
        print(f"์™„๋ฃŒ๋œ ํƒœ์Šคํฌ ๊ฒฐ๊ณผ: {result}")

โœ… ํŠน์ง•:

  • ๋ณ‘๋ ฌ ์‹คํ–‰
  • ์ˆœ์ฐจ ์‹คํ–‰
  • ๊ฒฐ๊ณผ ์ˆ˜์ง‘
  • ์™„๋ฃŒ ์ˆœ์„œ ๊ธฐ๋ฐ˜ ์ฒ˜๋ฆฌ
  • ํƒœ์Šคํฌ ๊ทธ๋ฃนํ™”

์‹ค์ œ ์‘์šฉ ์˜ˆ์ œ:

import aiohttp
import asyncio
from typing import List, Dict, Any

async def fetch_data(url: str) -> Dict[str, Any]:
    """URL์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ"""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()

async def fetch_all_data(urls: List[str]) -> List[Dict[str, Any]]:
    """์—ฌ๋Ÿฌ URL์—์„œ ๋ณ‘๋ ฌ๋กœ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ"""
    tasks = [fetch_data(url) for url in urls]
    return await asyncio.gather(*tasks)

async def process_user_data():
    """์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์˜ˆ์ œ"""
    # ์—ฌ๋Ÿฌ API ์—”๋“œํฌ์ธํŠธ์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
    user_data = await fetch_data("https://api.example.com/users/1")
    
    # ์‚ฌ์šฉ์ž์˜ ๊ฒŒ์‹œ๋ฌผ๊ณผ ๋Œ“๊ธ€ ๋ณ‘๋ ฌ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ
    posts_url = f"https://api.example.com/users/{user_data['id']}/posts"
    comments_url = f"https://api.example.com/users/{user_data['id']}/comments"
    
    posts, comments = await asyncio.gather(
        fetch_data(posts_url),
        fetch_data(comments_url)
    )
    
    # ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐ ๊ฒฐํ•ฉ
    result = {
        "user": user_data,
        "posts": posts,
        "comments": comments,
        "activity_score": len(posts) + len(comments)
    }
    
    return result


5๏ธโƒฃ ํƒ€์ž„์•„์›ƒ๊ณผ ์ทจ์†Œ

์ฝ”๋ฃจํ‹ด ์‹คํ–‰ ์ œ์–ด๋ฅผ ์œ„ํ•œ ํƒ€์ž„์•„์›ƒ ์„ค์ •๊ณผ ์ทจ์†Œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค.

async def long_operation():
    print("๊ธด ์ž‘์—… ์‹œ์ž‘")
    await asyncio.sleep(10)  # ๊ธด ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    print("๊ธด ์ž‘์—… ์™„๋ฃŒ")
    return "์™„๋ฃŒ"

async def with_timeout():
    try:
        # Python 3.11+
        async with asyncio.timeout(2.0):
            await long_operation()
            
        # Python 3.10 ์ดํ•˜
        # async with asyncio.timeout_at(asyncio.get_event_loop().time() + 2.0):
        #     await long_operation()
    except asyncio.TimeoutError:
        print('์ž‘์—… ์‹œ๊ฐ„ ์ดˆ๊ณผ')

async def cancellation_demo():
    try:
        task = asyncio.create_task(long_operation())
        await asyncio.sleep(1)
        task.cancel()
        await task
    except asyncio.CancelledError:
        print('์ž‘์—…์ด ์ทจ์†Œ๋จ')
        
# ์ทจ์†Œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ตฌํ˜„๋œ ์ž‘์—…
async def cancellable_operation():
    try:
        while True:
            print("์ž‘์—… ์ˆ˜ํ–‰ ์ค‘...")
            await asyncio.sleep(0.5)
    except asyncio.CancelledError:
        print("์ทจ์†Œ ์‹ ํ˜ธ ๊ฐ์ง€")
        # ์ •๋ฆฌ ์ž‘์—… ์ˆ˜ํ–‰
        print("๋ฆฌ์†Œ์Šค ์ •๋ฆฌ ์ค‘...")
        await asyncio.sleep(0.5)
        print("์ •๋ฆฌ ์™„๋ฃŒ")
        raise  # ์ทจ์†Œ ์‹ ํ˜ธ ์ „ํŒŒ

โœ… ํŠน์ง•:

  • ํƒ€์ž„์•„์›ƒ ์„ค์ •
  • ์ž‘์—… ์ทจ์†Œ ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ
  • ์ทจ์†Œ ์‹ ํ˜ธ ์ฒ˜๋ฆฌ
  • ์šฐ์•„ํ•œ ์ข…๋ฃŒ ๊ตฌํ˜„

ํƒ€์ž„์•„์›ƒ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ตฌํ˜„:

import functools
import asyncio
from typing import TypeVar, Callable, Awaitable, Optional, Any, cast

T = TypeVar('T')

def with_timeout(timeout: float):
    """
    ์ง€์ •๋œ ํƒ€์ž„์•„์›ƒ์œผ๋กœ ์ฝ”๋ฃจํ‹ด ํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
    
    Args:
        timeout: ํƒ€์ž„์•„์›ƒ(์ดˆ)
    
    ์˜ˆ์™ธ:
        asyncio.TimeoutError: ์ž‘์—…์ด ์ง€์ •๋œ ์‹œ๊ฐ„ ๋‚ด์— ์™„๋ฃŒ๋˜์ง€ ์•Š์œผ๋ฉด ๋ฐœ์ƒ
    """
    def decorator(func: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
        @functools.wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> T:
            return await asyncio.wait_for(func(*args, **kwargs), timeout=timeout)
        return wrapper
    return decorator

@with_timeout(2.0)
async def fetch_with_timeout(url: str) -> str:
    """2์ดˆ ํƒ€์ž„์•„์›ƒ์ด ์žˆ๋Š” URL ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ"""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()


6๏ธโƒฃ ์ฝ”๋ฃจํ‹ด๊ณผ ์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค ํ†ตํ•ฉ

์ฝ”๋ฃจํ‹ด๊ณผ ๋‹ค๋ฅธ ๋™์‹œ์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

import asyncio
import concurrent.futures
import time
import functools

def cpu_bound_task(x):
    """CPU ์ง‘์•ฝ์  ์ž‘์—… (์Šค๋ ˆ๋“œ/ํ”„๋กœ์„ธ์Šค ํ’€์—์„œ ์‹คํ–‰)"""
    result = 0
    for i in range(10**7):
        result += i + x
    return result

async def run_in_threadpool(func, *args):
    """ํ•จ์ˆ˜๋ฅผ ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์‹คํ–‰"""
    loop = asyncio.get_running_loop()
    with concurrent.futures.ThreadPoolExecutor() as pool:
        return await loop.run_in_executor(
            pool, functools.partial(func, *args)
        )

async def run_in_processpool(func, *args):
    """ํ•จ์ˆ˜๋ฅผ ํ”„๋กœ์„ธ์Šค ํ’€์—์„œ ์‹คํ–‰"""
    loop = asyncio.get_running_loop()
    with concurrent.futures.ProcessPoolExecutor() as pool:
        return await loop.run_in_executor(
            pool, functools.partial(func, *args)
        )

async def mixed_concurrency():
    """์ฝ”๋ฃจํ‹ด, ์Šค๋ ˆ๋“œ, ํ”„๋กœ์„ธ์Šค ํ˜ผํ•ฉ ์‚ฌ์šฉ"""
    # I/O ๋ฐ”์šด๋“œ ์ž‘์—…์€ ์ฝ”๋ฃจํ‹ด์œผ๋กœ
    io_task = asyncio.create_task(asyncio.sleep(1))
    
    # CPU ๋ฐ”์šด๋“œ ์ž‘์—…์€ ํ”„๋กœ์„ธ์Šค ํ’€๋กœ
    cpu_task1 = run_in_processpool(cpu_bound_task, 1)
    cpu_task2 = run_in_processpool(cpu_bound_task, 2)
    
    # ํŒŒ์ผ I/O๋Š” ์Šค๋ ˆ๋“œ ํ’€๋กœ (๋ธ”๋กœํ‚น I/O)
    file_task = run_in_threadpool(lambda: open('large_file.txt', 'r').read())
    
    # ๋ชจ๋“  ์ž‘์—… ์™„๋ฃŒ ๋Œ€๊ธฐ
    results = await asyncio.gather(
        io_task,
        cpu_task1,
        cpu_task2,
        file_task
    )
    
    return results

โœ… ํŠน์ง•:

  • ์ฝ”๋ฃจํ‹ด๊ณผ ์Šค๋ ˆ๋“œ ํ’€ ํ†ตํ•ฉ
  • ํ”„๋กœ์„ธ์Šค ํ’€ ํ™œ์šฉ
  • ๋ธ”๋กœํ‚น ์ฝ”๋“œ ์ฒ˜๋ฆฌ
  • ์ž‘์—… ์œ ํ˜•๋ณ„ ์ตœ์  ์‹คํ–‰ ๋ฐฉ์‹
  • ๋ฆฌ์†Œ์Šค ํšจ์œจ์„ฑ ๊ทน๋Œ€ํ™”


7๏ธโƒฃ ์‹ค์ „ ํŒจํ„ด๊ณผ ๊ณ ๊ธ‰ ์‚ฌ์šฉ๋ฒ•

์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ™œ์šฉ ๊ฐ€๋Šฅํ•œ ๋น„๋™๊ธฐ ํŒจํ„ด๊ณผ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•์ด๋‹ค.

์„ธ๋งˆํฌ์–ด๋ฅผ ํ™œ์šฉํ•œ ๋™์‹œ์„ฑ ์ œํ•œ:

import asyncio
import aiohttp
from typing import List, Dict

async def fetch_with_semaphore(semaphore, url):
    """์„ธ๋งˆํฌ์–ด๋กœ ๋™์‹œ ์š”์ฒญ ์ˆ˜ ์ œํ•œ"""
    async with semaphore:
        print(f"{url} ์š”์ฒญ ์‹œ์ž‘")
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                data = await response.json()
                print(f"{url} ์š”์ฒญ ์™„๋ฃŒ")
                return data

async def rate_limited_requests(urls: List[str], limit: int = 5):
    """๋™์‹œ ์š”์ฒญ ์ˆ˜๋ฅผ ์ œํ•œํ•˜์—ฌ API ํ˜ธ์ถœ"""
    semaphore = asyncio.Semaphore(limit)
    tasks = [fetch_with_semaphore(semaphore, url) for url in urls]
    return await asyncio.gather(*tasks)

๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์™€ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ:

import asyncio
from typing import AsyncIterator, List

async def async_range(start: int, stop: int, delay: float = 0.1) -> AsyncIterator[int]:
    """๋น„๋™๊ธฐ ๋ฒ”์œ„ ์ƒ์„ฑ๊ธฐ"""
    for i in range(start, stop):
        await asyncio.sleep(delay)
        yield i

async def process_stream(stream: AsyncIterator[int]) -> List[int]:
    """๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ"""
    result = []
    async for item in stream:
        result.append(item * 2)
    return result

async def demo_async_iterator():
    """๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ๋ฐ๋ชจ"""
    stream = async_range(0, 10)
    processed = await process_stream(stream)
    print(f"๊ฒฐ๊ณผ: {processed}")

๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž:

import asyncio
import aiofiles
from typing import AsyncIterator

class AsyncResource:
    """๋น„๋™๊ธฐ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ ์˜ˆ์ œ"""
    
    def __init__(self, name: str):
        self.name = name
        
    async def __aenter__(self):
        print(f"{self.name} ๋ฆฌ์†Œ์Šค ์ดˆ๊ธฐํ™” ์ค‘...")
        await asyncio.sleep(0.1)  # ์ดˆ๊ธฐํ™” ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        print(f"{self.name} ์ค€๋น„ ์™„๋ฃŒ")
        return self
        
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print(f"{self.name} ์ •๋ฆฌ ์ค‘...")
        await asyncio.sleep(0.1)  # ์ •๋ฆฌ ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        print(f"{self.name} ์ •๋ฆฌ ์™„๋ฃŒ")
        
    async def process(self, data: str) -> str:
        print(f"{self.name}์—์„œ ์ฒ˜๋ฆฌ: {data}")
        await asyncio.sleep(0.2)  # ์ฒ˜๋ฆฌ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        return f"{data} ์ฒ˜๋ฆฌ๋จ"

async def async_file_processing(filename: str) -> str:
    """๋น„๋™๊ธฐ ํŒŒ์ผ ์ฒ˜๋ฆฌ ์˜ˆ์ œ"""
    async with AsyncResource("ํŒŒ์ผ ์ฒ˜๋ฆฌ๊ธฐ") as processor:
        async with aiofiles.open(filename, mode='r') as file:
            content = await file.read()
            result = await processor.process(content)
        
        return result

โœ… ํŠน์ง•:

  • ์„ธ๋งˆํฌ์–ด ๊ธฐ๋ฐ˜ ๋™์‹œ์„ฑ ์ œ์–ด
  • ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ดํ„ฐ/์ œ๋„ˆ๋ ˆ์ดํ„ฐ
  • ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž
  • ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ ํŒจํ„ด
  • ๋ฆฌ์†Œ์Šค ํšจ์œจ์  ๊ด€๋ฆฌ


์ฃผ์š” ํŒ

โœ… ๋ชจ๋ฒ” ์‚ฌ๋ก€:

  • async/await ๋ฌธ๋ฒ• ์‚ฌ์šฉ: ์ตœ์‹  Python ๋น„๋™๊ธฐ ๋ฌธ๋ฒ•์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
  • ์ ์ ˆํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ตฌํ˜„: ๋ชจ๋“  ๋น„๋™๊ธฐ ์ž‘์—…์— try/except ๋ธ”๋ก ํ™œ์šฉ
  • ์ฝ”๋ฃจํ‹ด ์ทจ์†Œ ์ฒ˜๋ฆฌ ๊ตฌํ˜„: CancelledError๋ฅผ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜ ๋ฐฉ์ง€
  • ๋™์‹œ์„ฑ ์ œ์–ด ๋„๊ตฌ ํ™œ์šฉ: ์„ธ๋งˆํฌ์–ด๋‚˜ ๋ฝ์„ ํ™œ์šฉํ•˜์—ฌ ๋™์‹œ ์‹คํ–‰ ์ œํ•œ
  • ๋””๋ฒ„๊น… ๋กœ๊ทธ ์ถ”๊ฐ€: ๋น„๋™๊ธฐ ์ž‘์—… ์ถ”์ ์„ ์œ„ํ•œ ๋กœ๊น… ๊ตฌํ˜„
  • ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ตฌํ˜„: ์ž‘์—… ์‹œ๊ฐ„ ์ธก์ • ๋ฐ ๋ณ‘๋ชฉ ์ง€์  ์‹๋ณ„
  • ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์ฃผ์˜: ๋ฏธ์™„๋ฃŒ ํƒœ์Šคํฌ์™€ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๊ด€๋ฆฌ์— ์ฃผ์˜
  • ๋ธ”๋กœํ‚น ์ฝ”๋“œ ์ฒ˜๋ฆฌ: CPU ์ง‘์•ฝ์  ์ž‘์—…์€ ํ”„๋กœ์„ธ์Šค ํ’€๋กœ, ๋ธ”๋กœํ‚น I/O๋Š” ์Šค๋ ˆ๋“œ ํ’€๋กœ ์ด๋™
  • ๋™๊ธฐ ์ฝ”๋“œ์™€ ํ†ตํ•ฉ: ๊ธฐ์กด ๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋น„๋™๊ธฐ ํ™˜๊ฒฝ์— ํ†ตํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์ˆ™์ง€
  • ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•๋ก : ๋น„๋™๊ธฐ ์ฝ”๋“œ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋ก  ์ ์šฉ
  • ํƒ€์ž„์•„์›ƒ ์„ค์ •: ๋ชจ๋“  ์™ธ๋ถ€ ๋ฆฌ์†Œ์Šค ํ˜ธ์ถœ์— ํƒ€์ž„์•„์›ƒ ์„ค์ •
  • ์šฐ์•„ํ•œ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ ์‹œ ์‹คํ–‰ ์ค‘์ธ ํƒœ์Šคํฌ ์ •๋ฆฌ
  • ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ ์ฃผ์˜: Python ๋ฒ„์ „๋ณ„ asyncio API ์ฐจ์ด ์ธ์ง€
  • ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ: aiohttp, aiofiles ๋“ฑ์˜ ๋น„๋™๊ธฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ
  • ํƒœ์Šคํฌ ๊ทธ๋ฃนํ™”: ๊ด€๋ จ ํƒœ์Šคํฌ ๊ทธ๋ฃนํ™” ๋ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ


โš ๏ธ **GitHub.com Fallback** โš ๏ธ