3.1 ๋ชจ๋ asyncio
๋น๋๊ธฐ ์์ ์ ์ํ ์ค๋ ๋๋ฅผ ์ด์ ๋ ์๋ฌด๋ ๋ง๋ค์ง ์์. ๋ฌผ๋ก ๋ง๋ค ์๋ ์์ง๋ง, ๊ทธ๋ฐ ์์ ์ ๋๋ฌด ์ ์์ค์ด๋ผ๊ณ ์ฌ๊ฒจ์ง๊ณ ํ๋ ์์ํฌ ๊ฐ๋ฐ์๋ค๋ง ์ฌ์ฉํ ์ ๋์ผ. ๊ทธ๋ง์ ๋ ์์ ํ ํ์ํ ๋๋ง ๊ทธ๋ ๊ฒ ํด.
์ง๊ธ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ, ๋์์ async/await
๊ทธ๋ฆฌ๊ณ ์ฝ๋ฃจํด๊ณผ ํ์คํฌ๊ฐ ๋์ธ์ผ. ํ์ง๋ง ์ฐจ๊ทผ์ฐจ๊ทผ ์ดํด๋ณด์~
์ญ์ฌ์ ์ผ๋ก
์ฒ์์ Python์์๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ๋ฃจํด๊ณผ ์์ฑ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ฉํ์ด.
๊ทธ๋ฌ๋ค๊ฐ Python 3.4์์๋ asyncio
๋ชจ๋์ด ๋์์ด
(๊ฐ๋ async IO
๋ผ๊ณ ๋ ๋ถ๋ฆฌ๋๋ฐ)
์ฌ๊ธฐ์๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ํ ๋ฉ์ปค๋์ฆ์ด ๊ตฌํ๋์ด์์ด.
Python 3.5์๋ async/await
๊ตฌ์กฐ๊ฐ ์ถ๊ฐ๋์ง.
์ด์ ์ฝ๊ฐ์ ๋ฐฐ๊ฒฝ ์ ๋ณด๋ฅผ ์๋ ค์ค๊ฒ. ๋จผ์ ์ด๋ค์ ๋ํด ๊ฐ๋จํ ์ค๋ช ํ๊ณ , ์์ธํ ์ค๋ช ํ๊ณ , ๊ทธ ํ์ ๋ ์์ธํ ์ค๋ช ํ ๊ฒ. ์๋ํ๋ฉด ๊ฑฐ์ ๋ชจ๋๊ฐ ํจ๊ป ์๋ํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ฒ๋ค์ ์ฐธ์กฐํ์ง ์๊ณ ํ ๊ฐ์ง๋ฅผ ์์ธํ ์ค๋ช ํ๊ธฐ๋ ์ด๋ ค์.
๋ชจ๋ asyncio
๋ชจ๋ asyncio
๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋จ์ ์์ฑํ๊ธฐ ์ํ ๊ฒ์ด๊ณ ,
ํ์คํฌ๋ค์ ๋ณ๋ ฌ๋ก ์คํํ ์ ์๋ ๊ธฐ๋ฅ์ ์ง์ํด. ๋น๋๊ธฐ ์
์ถ๋ ฅ ์์
, ํ์ด๋จธ, ์์ผ, ์ฝ๋ฃจํด ์คํ ๋ฐ ๋ฉํฐ์ค๋ ๋ฉ์ ์ง์ํ๊ณ ,
ํ๋ ๋๋ ์ฌ๋ฌ ๊ฐ์ ์ด๋ฒคํธ ๋ฃจํ์์ ์๋ํด.
์ฝ๋ฃจํด (Coroutines)
์ฝ๋ฃจํด์
๋น๋๊ธฐ ํจ์๋ก,
async def
ํค์๋๋ฅผ ์ฌ์ฉํด์ ์ ์๋ผ. ์ฝ๋ฃจํด์ await ํค์๋๋ฅผ ์ฌ์ฉํด์ ์์ ์ ์คํ์ ์ผ์ ์ค๋จํ ์ ์์ด
,
๊ทธ ๋์์ ๋ค๋ฅธ ์ฝ๋ฃจํด์ด ์คํ๋ ์ ์์ง
.
import asyncio
# ๋น๋๊ธฐ ํจ์ (์ฝ๋ฃจํด) ์ ์
async def main():
print('Hello ...')
# 1์ด ๋์ ์คํ ์ค์ง
await asyncio.sleep(1)
print('... World!')
# ์ด๋ฒคํธ ๋ฃจํ์์ ๋น๋๊ธฐ ํจ์ main() ์คํ
asyncio.run(main())
์ด๋ฒคํธ ๋ฃจํ (Event Loop)
์ด๋ฒคํธ ๋ฃจํ๋ ์ฝ๋ฃจํด, ํ์คํฌ ๋ฐ ๊ธฐํ ๋น๋๊ธฐ ์์
์ ์คํ์ ๊ด๋ฆฌํด. asyncio.run()
ํธ์ถ์ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์์ํ๊ณ ์ฝ๋ฃจํด์ด ์๋ฃ๋ ๋๊น์ง ์คํํด.
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
# ํ์ฌ ์ด๋ฒคํธ ๋ฃจํ ๊ฐ์ ธ์ค๊ธฐ
loop = asyncio.get_event_loop()
# ์ฝ๋ฃจํด์ด ์๋ฃ๋ ๋๊น์ง ์คํ
loop.run_until_complete(main())
# ๋ชจ๋ ํ์คํฌ ์๋ฃ ํ ์ด๋ฒคํธ ๋ฃจํ ๋ซ๊ธฐ
loop.close()
ํ์คํฌ (Tasks)
ํ์คํฌ๋ ์ฝ๋ฃจํด์ ๋ณ๋ ฌ๋ก ์คํํ ์ ์๊ฒ ํด. asyncio.create_task()
๋ asyncio.ensure_future()
๋ก ์์ฑ๋ผ.
import asyncio
# ์ง์ฐ ์คํ๋๋ ์ฝ๋ฃจํด ์ ์
async def say_after(delay, what):
# ์ง์ ๋ ์๊ฐ ๋์ ์คํ ์ค์ง
await asyncio.sleep(delay)
print(what)
# ๋ฉ์ธ ์ฝ๋ฃจํด
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())
ํจ์ฒ (Futures)
Future
๊ฐ์ฒด๋ ๋น๋๊ธฐ ์์
์ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ด๋ฉฐ, ๋ฏธ๋์ ์ฌ์ฉํ ์ ์์ด. ์๋ฅผ ๋ค์ด ๋น๋๊ธฐ ํ์คํฌ๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋๋ฐ ์ฌ์ฉ๋ผ.
import asyncio
# ๊ธด ์์
์ ๋ชจ๋ฐฉํ ์ฝ๋ฃจํด ์ ์
async def long_running_task():
print('Task started')
# 3์ด ๋์ ์คํ ์ค์ง
await asyncio.sleep(3)
print('Task finished')
return 'Result'
# ๋ฉ์ธ ์ฝ๋ฃจํด
async def main():
# ํ์คํฌ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํ ํจ์ฒ ์์ฑ
future = asyncio.ensure_future(long_running_task())
# ํ์คํฌ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ ๊ฒฐ๊ณผ ํ๋
result = await future
print(f'Task result: {result}')
# ๋ฉ์ธ ์ฝ๋ฃจํด ์คํ
asyncio.run(main())
3.2 ๋น๋๊ธฐ ํจ์ โ async def
๋น๋๊ธฐ ํจ์๋ ์ผ๋ฐ ํจ์์ ๋์ผํ๊ฒ ์ ์ธ๋์ง๋ง, def
ํค์๋ ์์ async
๋ฅผ ๋ถ์ฌ์ผ ํด.
async def ํจ์์ด๋ฆ(๋งค๊ฐ๋ณ์):
ํจ์ ์ฝ๋
๋น๋๊ธฐ ํจ์๋ ์ผ๋ฐ ํจ์์ฒ๋ผ ์ ์ธ๋๊ณ ํธ์ถ๋์ง๋ง ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐํํ๋ ๊ฒ ์๋๋ผ ํน๋ณํ ๊ฐ์ฒด, ์ฝ๋ฃจํด์ ๋ฐํํด.
์ด๊ฒ์ ์ค์ ๋ก ํ์ธํ ์๋ ์์ด:
import asyncio
async def main():
print("Hello World")
# ์ฝ๋ฃจํด์ ๋ฐํํ๋ ๋น๋๊ธฐ ํจ์ ํธ์ถ
result = main()
# ๊ฒฐ๊ณผ ํ์
ํ์ธ
print(type(result)) # <class 'coroutine'>
๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋๊ฑธ๊น? ๋น์ ์ด ํจ์๋ฅผ async๋ก ํ์ํ ๋, ์ฌ์ค์ ์ด ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ถ๊ฐํ๋ ๊ฑฐ๋ ๋น์ทํด:
def async_decorator(func):
# Task ๊ฐ์ฒด ์์ฑ
task = Task()
# ์ฐ๋ฆฌ ํจ์ func๋ฅผ ์ ๋ฌํ์ฌ ์ด๋ฅผ ์คํํ๊ฒ ํจ
task.target = func
# ํด๋น task ๊ฐ์ฒด๋ฅผ ์ด๋ฒคํธ ๋ฃจํ์ ํ์คํฌ ํ์ ์ถ๊ฐ
eventloop.add_task(task)
# task ๊ฐ์ฒด ๋ฐํ
return task
๊ทธ๋ฆฌ๊ณ ๋น์ ์ ์ฝ๋๋ ์ด์ฒ๋ผ ๋ณ๊ฒฝ๋ผ:
import asyncio
@async_decorator
def main():
print("Hello World")
result = main()
print(type(result)) # <class 'coroutine'>
์ด ๋น์ ์ ์๋ฏธ๋ ๋ค์๊ณผ ๊ฐ์:
๋น๋๊ธฐ ํจ์๋ฅผ ํธ์ถํ๋ฉด ํน๋ณํ ๊ฐ์ฒด Task
๊ฐ ์์ฑ๋ผ,
์ด ๊ฐ์ฒด๋ ๋น์ ์ ํจ์๋ฅผ ์คํํ ์์ ์ด์ง๋ง, ๋ฏธ๋์ ์ด๋ ์์ ์ ์คํ๋ ๊ฑฐ์ผ.
0.0001 ์ด ํ์ผ ์๋ ์๊ณ , 10์ด ํ์ผ ์๋ ์์ด.
์ด task ๊ฐ์ฒด๊ฐ ๋น์ ์ ๋น๋๊ธฐ ํจ์ ํธ์ถ์ ๊ฒฐ๊ณผ๋ก ์ฆ์ ๋ฐํ๋ผ.์ด๊ฒ์ด ๋ฐ๋ก ์ฝ๋ฃจํด์ด์ผ. ๋น์ ์ ๋น๋๊ธฐ ํจ์๋ ์์ง ์คํ๋์ง ์์์ ์๋ ์์ง๋ง, task ๊ฐ์ฒด(์ฝ๋ฃจํด)๋ ์ด๋ฏธ ์กด์ฌํด.
์ ์ด task
๊ฐ์ฒด(์ฝ๋ฃจํด)๊ฐ ํ์ํ ๊น? ์ฌ์ค ํ ์ ์๋ ์ผ์ ๋ง์ง ์์ง๋ง, 3๊ฐ์ง ์ผ์ ๊ฐ๋ฅํด:
- ๋น๋๊ธฐ ํจ์๊ฐ ์คํ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ธฐ.
- ๋น๋๊ธฐ ํจ์๊ฐ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ณ , ์ฝ๋ฃจํด์์ ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ.
- 10๊ฐ(์ด๋ค ์ซ์๋ )์ ๋น๋๊ธฐ ํจ์๊ฐ ์คํ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ธฐ.
์ด๋ป๊ฒ ํ๋์ง๋ ์๋์์ ์ค๋ช ํ ๊ฒ.
3.3 ์ฐ์ฐ์ await
์ฝ๋ฃจํด๊ณผ ๊ด๋ จ๋ ๋๋ถ๋ถ์ ์์
์ "๋น๋๊ธฐ ํจ์์ ์คํ์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ"์์ ์์ํด. ๊ทธ๋์ ์ด ์์
์ ์ํ ํน๋ณํ ์ฐ์ฐ์ await
๊ฐ ์์ด.
๋จ์ํ ์ฝ๋ฃจํด ์์ ์ด๋ฅผ ์ฐ๋ฉด ๋ผ:
await ์ฝ๋ฃจํด
๋๋ ๋ฐ๋ก ๋น๋๊ธฐ ํจ์ ํธ์ถ ์์ ์์ฑํ๋ฉด ๋ผ:
await ๋น๋๊ธฐ_ํจ์(์ธ์)
Python์ด ์ฐ์ฐ์ await
๋ฅผ ๋ง๋ฌ์ ๋, ํ์ฌ ํจ์์ ์คํ์ ์ผ์ ์ค์งํ๊ณ
์ฝ๋ฃจํด์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค โ ์ฝ๋ฃจํด์ด ์ฐธ์กฐํ๋ ๋น๋๊ธฐ ํจ์๊ฐ ์๋ฃ๋ ๋๊น์ง.
์ค์!
์ฐ์ฐ์ await
๋ ์ค์ง ๋น๋๊ธฐ ํจ์ ๋ด์์๋ง
๋ค๋ฅธ ์ฝ๋ฃจํด ๋๋ ๋น๋๊ธฐ ์์
์ด ์๋ฃ๋ ๋๊น์ง ์คํ์ ์ค์งํ๋ ๋ฐ ์ฌ์ฉ๋ผ.
์ด๋ ๋น๋๊ธฐ ํจ์ ํธ์ถ ์ฌ์ด์ ์ ํ ๊ณผ์ ์ ๊ฐ์ํํ๊ธฐ ์ํด์์ผ. await
ํธ์ถ์ ์ค์ ๋ก "์ฌ๊ธฐ์ ์ด๋ค ์๊ฐ์ ๊ธฐ๋ค๋ฆด๊ฑฐ๋๊น โ ๋ค๋ฅธ ๋น๋๊ธฐ ํจ์๋ค์ ์คํํ์ธ์"๋ผ๋ ์ ์ธ์ด์ผ.
์์:
import asyncio
# ๋น๋๊ธฐ ํจ์ ์ ์
async def async_print(text):
print(text)
# ๋ฉ์ธ ๋น๋๊ธฐ ํจ์
async def main():
# ๋น๋๊ธฐ ํจ์ ์คํ์ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํด await ์ฌ์ฉ
await async_print("Hello World")
# ๋ฉ์ธ ์ด๋ฒคํธ ๋ฃจํ ์คํ ๋ฐ ์ฝ๋ฃจํด main() ์ํ
asyncio.run(main()) # ๋น๋๊ธฐ ํจ์ ์คํ
์ฌ์ค await
์ฐ์ฐ์๋ ๋ ์๋ฆฌํ๊ฒ ์๋ํด โ ๋น๋๊ธฐ ํจ์์ ์คํ ๊ฒฐ๊ณผ๋ ๋ฐํํด
๊ทธ ํจ์์์ ํธ์ถ๋๋.
์์:
import asyncio
# ๋ ์ซ์๋ฅผ ๋ํ๋ ๋น๋๊ธฐ ํจ์ ์ ์
async def async_add(a, b):
return a + b
# ๋ฉ์ธ ๋น๋๊ธฐ ํจ์
async def main():
# async_add์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด await ์ฌ์ฉ
sum = await async_add(100, 200)
print(sum)
# ๋ฉ์ธ ์ด๋ฒคํธ ๋ฃจํ ์คํ ๋ฐ ์ฝ๋ฃจํด main() ์ํ
asyncio.run(main()) # ๋น๋๊ธฐ ํจ์ ์คํ
๊ฒฐ๋ก ์ ์ผ๋ก, ์ฐ์ฐ์ await
๋:
- ๋ค๋ฅธ ์ฝ๋ฃจํด์ด๋ ๋น๋๊ธฐ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ํ์ฌ ๋น๋๊ธฐ ํจ์๋ฅผ ์ค๋จํด.
- ๋น๋๊ธฐ ์์ ๋๋ ์ฝ๋ฃจํด์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํด.
- ์ค์ง ๋น๋๊ธฐ ํจ์ ๋ด์์๋ง ์ฌ์ฉํ ์ ์์ด.
GO TO FULL VERSION