Asyncio - λΉλκΈ° νλ‘κ·Έλλ°
μ£Όμ κ°λ
νμ΄μ¬μ asyncio λͺ¨λμ λΉλκΈ° I/O, μ΄λ²€νΈ 루ν, coroutines λ° νμ€ν¬(task) κ΄λ¦¬ λ±μ ν΅ν΄ λΉλκΈ° νλ‘κ·Έλλ°μ μ§μνλ νμ€ λΌμ΄λΈλ¬λ¦¬μ λλ€. asyncioλ₯Ό μ¬μ©νλ©΄ λ€νΈμν¬ λ° μΉ μμΌ, λ°μ΄ν°λ² μ΄μ€, νμΌ I/O λ±μ μμ μ ν¨μ¨μ μΌλ‘ μ²λ¦¬ν μ μμ΅λλ€.
- μ΄λ²€νΈ 루ν (Event Loop):
- μ΄λ²€νΈ 루νλ μ½λ£¨ν΄κ³Ό μ½λ°±μ κ΄λ¦¬νκ³ , I/O μμ μ΄ μλ£λ λκΉμ§ κΈ°λ€λ¦¬λ μν μ ν©λλ€.
- asyncio.run() ν¨μλ₯Ό ν΅ν΄ μ΄λ²€νΈ 루νλ₯Ό μμν μ μμ΅λλ€.
- μ½λ£¨ν΄ (Coroutine):
- async defλ‘ μ μλ ν¨μμ λλ€.
- await ν€μλλ₯Ό μ¬μ©νμ¬ λ€λ₯Έ μ½λ£¨ν΄μ΄λ λΉλκΈ° μμ μ κΈ°λ€λ¦½λλ€.
- νμ€ν¬ (Task):
- μ½λ£¨ν΄μ μ΄λ²€νΈ 루νμμ μ€νν μ μλ λ¨μλ‘ λ³νν©λλ€.
- asyncio.create_task()λ₯Ό μ¬μ©νμ¬ νμ€ν¬λ₯Ό μμ±νκ³ , μ΄λ₯Ό ν΅ν΄ μ¬λ¬ μ½λ£¨ν΄μ λμμ μ€νν μ μμ΅λλ€.
- ν¨μ² (Future):
- λΉλκΈ° μ°μ°μ κ²°κ³Όλ₯Ό λνλ λλ€.
- μ½λ£¨ν΄μ΄λ νμ€ν¬μ κ²°κ³Όλ₯Ό ννν λ μ¬μ©λ©λλ€.
μ£Όμ ν¨μ λ° μ¬μ©λ²
μ΄λ²€νΈ 루ν μ€ν
import asyncio
async def main():
print("Hello, asyncio!")
# μ΄λ²€νΈ 루ν μ€ν
asyncio.run(main())
μ½λ£¨ν΄ μ μ λ° μ€ν
import asyncio
async def say_hello():
print("Hello!")
await asyncio.sleep(1)
print("Goodbye!")
async def main():
await say_hello()
asyncio.run(main())
νμ€ν¬ μμ± λ° μ€ν
import asyncio
async def say_after(delay, message):
await asyncio.sleep(delay)
print(message)
async def main():
task1 = asyncio.create_task(say_after(1, "Hello"))
task2 = asyncio.create_task(say_after(2, "World"))
await task1
await task2
asyncio.run(main())
κ³ κΈ κΈ°λ₯
μ¬λ¬ νμ€ν¬ λμμ μ€ν
import asyncio
async def say_hello():
await asyncio.sleep(1)
print("Hello!")
async def say_goodbye():
await asyncio.sleep(2)
print("Goodbye!")
async def main():
await asyncio.gather(say_hello(), say_goodbye())
asyncio.run(main())
νμμμ μ€μ
import asyncio
async def long_running_task():
await asyncio.sleep(5)
return "Completed"
async def main():
try:
result = await asyncio.wait_for(long_running_task(), timeout=3)
print(result)
except asyncio.TimeoutError:
print("Task timed out")
asyncio.run(main())
λΉλκΈ° I/O μμ
import asyncio
async def read_file(file_path):
loop = asyncio.get_event_loop()
with open(file_path, 'r') as file:
data = await loop.run_in_executor(None, file.read)
return data
async def main():
content = await read_file('example.txt')
print(content)
asyncio.run(main())
μμ½
asyncioλ νμ΄μ¬μμ λΉλκΈ° νλ‘κ·Έλλ°μ μ½κ² ꡬνν μ μλλ‘ λ€μν λꡬμ κΈ°λ₯μ μ 곡ν©λλ€. μ΄λ²€νΈ 루νλ₯Ό ν΅ν΄ μ½λ£¨ν΄κ³Ό νμ€ν¬λ₯Ό κ΄λ¦¬νκ³ , λ€νΈμν¬μ νμΌ I/O κ°μ λΉλκΈ° μμ μ ν¨μ¨μ μΌλ‘ μ²λ¦¬ν μ μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ μλ΅μ±μ΄ λκ³ μμμ ν¨μ¨μ μΌλ‘ μ¬μ©νλ νλ‘κ·Έλ¨μ μμ±ν μ μμ΅λλ€.
βοΈμ¬κΈ°κΉμ§κ° μΉ νμ΄μ§ λ° GPTμ λμμ λ°μ ν¬μ€ν μ λλ€.
βοΈ μ¬κΈ°λΆν°λ κ°μλ₯Ό ν΅ν΄ νμ΅ν λ΄μ© μ 리μ λλ€.
κ°μ
import asyncio
import time
async def sleep():
await asyncio.sleep(1)
async def sum(name, numbers):
start = time.time()
total = 0
for number in numbers:
await sleep()
total += number
print(f'μμ
μ€={name}, number={number}, total={total}')
end = time.time()
print(f'μμ
λͺ
={name}, κ±Έλ¦°μκ°={end-start}')
return total
async def main():
start = time.time()
task1 = asyncio.create_task(sum("A", [1, 2]))
task2 = asyncio.create_task(sum("B", [1, 2, 3]))
await task1
await task2
result1 = task1.result()
result2 = task2.result()
end = time.time()
print(f'μ΄ν©={result1+result2}, μ΄μκ°={end-start}')
if __name__ == "__main__":
asyncio.run(main())
ν¨μλ₯Ό λΉλκΈ°λ‘ νΈμΆνλ €λ©΄ μ΄λ κ² def μμ asyncλΌλ ν€μλλ₯Ό λ£μΌλ©΄ λλ€. κ·Έλ¬λ©΄ μ΄μ μ΄ ν¨μλ λΉλκΈ° ν¨μκ° λλ€. μ΄λ asyncλ₯Ό μ μ©ν λΉλκΈ° ν¨μλ₯Ό μ½λ£¨ν΄μ΄λΌ λΆλ₯Έλ€.
λν, μ½λ£¨ν΄ μμμ λ€λ₯Έ μ½λ£¨ν΄μ νΈμΆν λλ await sleep()κ³Ό κ°μ΄ awaitλ₯Ό ν¨μλͺ μμ λΆμ¬ νΈμΆν΄μΌ νλ€. μ½λ£¨ν΄ μν μ€ await μ½λ£¨ν΄μ λ§λλ©΄ awaitλ‘ νΈμΆν μ½λ£¨ν΄μ΄ μ’ λ£λ λκΉμ§ κΈ°λ€λ¦¬μ§ μκ³ μ μ΄κΆμ λ©μΈ μ€λ λλ λ€λ₯Έ μ½λ£¨ν΄μΌλ‘ λκΈ΄λ€. μ΄λ¬ν λ°©μμ λλΈλ‘νΉ(non-blocking)μ΄λΌ νλ€. κ·Έλ¦¬κ³ νΈμΆν μ½λ£¨ν΄μ΄ μ’ λ£λλ©΄ μ΄λ²€νΈμ μν΄ λ€μ κ·Έ μ΄ν μμ μ΄ μνλλ€.
μ¬κΈ°μ νλ λμ¬κ²¨λ΄μΌ ν μ μ sleep() ν¨μμμ time.sleep(1) λμ asyncio.sleep(1)λ₯Ό μ¬μ©ν λΆλΆμ΄λ€. μ½λ£¨ν΄μ΄ μλ time.sleep(1)μ μ¬μ©νλ€λ©΄ awaitκ° μ μ©λμ§ μμ μ€ν μκ°μ μ€μΌ μ μλ€.
main() ν¨μμμ μ¬μ©ν asyncio.create_task()λ μνν μ½λ£¨ν΄ μμ (νμ€ν¬)μ μμ±νλ€. μ¬κΈ°μλ μμ μ μμ±ν λΏμ΄μ§ μ€μ λ‘ μ½λ£¨ν΄μ΄ μνλλ κ²μ μλλ€. μ€μ μ½λ£¨ν΄ μ€νμ await νμ€ν¬κ° λ΄λΉνλ€. κ·Έλ¦¬κ³ μ€ν νμ€ν¬μ κ²°κ΄κ°μ νμ€ν¬.result()λ‘ μ»μ μ μλ€.
asyncio.create_task()λ μ½λ£¨ν΄μ λμμ μ€ννλ λ° κΌ νμνλ€. λ€μμ²λΌ νμ€ν¬κ° μλ awaitλ‘ μ½λ£¨ν΄μ μ€ννλ€λ©΄ μ½λ£¨ν΄μ΄ λμμ μ€νλμ§ μκ³ νλμ© μ°¨λ‘λ‘ μ€νλμ΄ μ΄λμ΄ μμ κ²μ΄λ€.
result1 =await sum("A", [1, 2])
result2 =await sum("B", [1, 2, 3])
asyncio.run(main())μ λ° λ£¨νλ₯Ό μμ±νμ¬ main() μ½λ£¨ν΄μ μ€ννλ€. μ½λ£¨ν΄μ μ€ννλ €λ©΄ λ° λ£¨νκ° λ°λμ νμνλ€. μ½λ£¨ν΄μ΄ λͺ¨λ λΉλκΈ°μ μΌλ‘ μ€νλκΈ° λλ¬Έμ κ·Έ μμκ³Ό μ’ λ£λ₯Ό κ°μ§ν μ μλ μ΄λ²€νΈ 루νκ° λ°λμ νμνκΈ° λλ¬Έμ΄λ€.
μ΄ μ½λλ₯Ό μ€νν κ²°κ³Όλ λ€μκ³Ό κ°λ€.
c:\\projects\\pylib>python asyncio_sample.py
μμ
μ€=A, number=1, total=1
μμ
μ€=B, number=1, total=1
μμ
μ€=A, number=2, total=3
μμ
λͺ
=A, κ±Έλ¦°μκ°=2.000617742538452
μμ
μ€=B, number=2, total=3
μμ
μ€=B, number=3, total=6
μμ
λͺ
=B, κ±Έλ¦°μκ°=3.000927209854126
μ΄ν©=9, μ΄μκ°=3.000927209854126
A μμ κ³Ό B μμ μ κ΅λλ‘ νΈμΆνλ€. (μ μ΄κΆμ΄ awaitμ μν΄ κ³μ λ°λλ€λ κ²μ μ μ μλ€.) κ·Έλ¦¬κ³ μκ°λ 5μ΄ κ±Έλ¦¬λ κ²μ΄ 3μ΄λ§ κ±Έλ¦¬κ² λλ―λ‘ A, B μμ μ΄ μμ ν λΉλκΈ°μ μΌλ‘ λμνλ€λ κ²μ μ μ μλ€.
λΉμ·ν μμ
import asyncio
import time
# Sync ν¨μ
def execute_calc_sync(name, n):
for i in range(1, n+1):
print(f"{name} -> {i} of {n} is calculating...")
time.sleep(1)
print(f"{name} is done!")
def process_sync():
start = time.time()
execute_calc_sync('one', 3)
execute_calc_sync('two', 2)
execute_calc_sync('three', 1)
end = time.time()
print(f"total seconds : {end - start}")
# Async ν¨μ
async def execute_calc_async(name, n):
for i in range(1, n+1):
print(f"{name} -> {i} of {n} is calculating...")
await asyncio.sleep(1)
print(f"{name} is done!")
async def process_async():
start = time.time()
await asyncio.gather(
execute_calc_async('one', 1),
execute_calc_async('two', 2),
execute_calc_async('three', 3)
)
end = time.time()
print(f"total seconds : {end - start}")
if __name__ == "__main__":
# Sync μ€ν
# process_sync()
# Async μ€ν
# νμ΄μ¬ 3.7 μ΄μ
asyncio.run(process_async())
one -> 1 of 1 is calculating...
two -> 1 of 2 is calculating...
three -> 1 of 3 is calculating...
one is done!
two -> 2 of 2 is calculating...
three -> 2 of 3 is calculating...
two is done!
three -> 3 of 3 is calculating...
three is done!
total seconds : 3.0082101821899414
Syncν¨μλ‘ μ€ννλ©΄ 6μ΄κ° κ±Έλ¦°λ€. μ½λμμ ASync ν¨μλΆλΆμ μ§μ€νμ. mainμμ asyncio.runννλ‘ asyncν¨μλ₯Ό νΈμΆνλ€. κ·Έλ¦¬κ³ μ¬λ¬κ°μ λΉλκΈ° ν¨μλ₯Ό λ¬Άμ΄μ awaitμΌλ‘ νΈμΆν μ μλ await asyncio,gatherλ₯Ό μ¬μ©νλ€.
μ°Έκ³ ν λ§ν λ¬Έμ
071 λΉλκΈ° λ°©μμΌλ‘ νλ‘κ·Έλλ°νλ €λ©΄? β asyncio