๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ - asyncio ๋ฑ
๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ - asyncio ๋ฑ ๊ด๋ จ
ํ์ด์ฌ์ ๋ค์ํ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๊ณตํ์ฌ ๋น๋๊ธฐ I/O ๋ฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค. ์ด ๊ธ์์๋ ํ์ด์ฌ์ ์ฃผ์ ๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Twisted
, Tornado
, Gevent
, asyncio
๋ฅผ ์๊ฐํ๊ณ , ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํน์ง๊ณผ ์ฌ์ฉ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
ํน์ง | Twisted | Tornado | Gevent | asyncio |
---|---|---|---|---|
๋์ ์๊ธฐ | 2002๋ | 2009๋ | 2009๋ | 2014๋ (Python 3.4) |
๋น๋๊ธฐ ๋ฐฉ์ | ์ด๋ฒคํธ ๋๋ฆฌ๋ธ(event-driven) | ์ด๋ฒคํธ ๋ฃจํ(event loop) | ๊ทธ๋ฆฐ ์ค๋ ๋(green threads) | ์ฝ๋ฃจํด(coroutines) |
์ฃผ์ ์ฌ์ฉ ์ฌ๋ก | ๋ค์ํ ๋คํธ์ํฌ ํ๋กํ ์ฝ ์ง์ | ๋น๋๊ธฐ ์น ์๋ฒ, ์น ์ ํ๋ฆฌ์ผ์ด์ | ๋น๋๊ธฐ ๋คํธ์ํฌ, I/O ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ | ๋ค์ํ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ |
๋คํธ์ํฌ ํ๋กํ ์ฝ | HTTP, FTP, SMTP ๋ฑ ๋ค์ํ ํ๋กํ ์ฝ ์ง์ | HTTP, ์น์์ผ | HTTP, ์น์์ผ | HTTP, ์น์์ผ |
์ฃผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | twisted.web, twisted.conch ๋ฑ | tornado.web, tornado.websocket ๋ฑ | gevent.pywsgi, gevent.socket ๋ฑ | aiohttp, Sanic, FastAPI ๋ฑ |
์ฝ๋ ์์ฑ ๋ฐฉ์ | ์ฝ๋ฐฑ(callback) ๊ธฐ๋ฐ | ์ฝ๋ฐฑ(callback) ๋ฐ Future ๊ธฐ๋ฐ | ๋๊ธฐ์ ์ฝ๋๋ฅผ ๋น๋๊ธฐ๋ก ๋ณํ | async/await ๋ฌธ๋ฒ |
ํ์ต ๊ณก์ | ๋์ | ์ค๊ฐ | ๋ฎ์ | ์ค๊ฐ |
์ปค๋ฎค๋ํฐ ์ง์ | ์ค๊ฐ | ์ค๊ฐ | ๋ฎ์ | ๋์ |
1. Twisted
Twisted๋ ํ์ด์ฌ์์ ๊ฐ์ฅ ์ค๋๋ ๋น๋๊ธฐ ๋คํธ์ํฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋๋ก, ๋ค์ํ ๋คํธ์ํฌ ํ๋กํ ์ฝ์ ์ง์ํฉ๋๋ค. ๋ณต์กํ ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋ ์ ์ฉํ๋ฉฐ, ํ๋ถํ ๊ธฐ๋ฅ๊ณผ ํ์ฅ์ฑ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ Twisted๋ ๋ณต์กํ API์ ๋ฌธ์ํ ๋ฌธ์ ๋ก ์ธํด ์ฌ์ฉ์ด ์ด๋ ต๋ค๋ ํ๊ฐ๋ฅผ ๋ฐ์์ต๋๋ค.
- ๋ค์ํ ๋คํธ์ํฌ ํ๋กํ ์ฝ ์ง์ (HTTP, FTP, SMTP, ๋ฑ)
- ์ด๋ฒคํธ ๋๋ฆฌ๋ธ(event-driven) ์ํคํ ์ฒ
- ๋์ ํ์ฅ์ฑ๊ณผ ์ ์ฐ์ฑ
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.resource import Resource
class HelloResource(Resource):
isLeaf = True
def render_GET(self, request):
return b"Hello, world!"
resource = HelloResource()
factory = Site(resource)
reactor.listenTCP(8080, factory)
reactor.run()
2. Tornado
Tornado๋ ๋น๋๊ธฐ ์น ํ๋ ์์ํฌ๋ก, ํนํ ์น ์๋ฒ์ ๊ฐ์ I/O ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค. ๋น ๋ฅธ ์๋์ ํ์ฅ์ฑ์ ์ ๊ณตํ๋ฉฐ, ๋น๋๊ธฐ ๋คํธ์ํฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก๋ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. Twisted์ ๋นํด ์ฌ์ฉ์ด ๋ ๊ฐํธํ๊ณ , ๋น๋๊ธฐ ์น ํ๋ ์์ํฌ๋ก ๋ง์ด ์ฑํ๋์์ต๋๋ค.
- ๋์ ์ฑ๋ฅ์ ๋น๋๊ธฐ ์น ์๋ฒ
- ์น์์ผ ๋ฐ ์ฅ๊ธฐ ํด๋ง(long-polling) ์ง์
- ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ธ API
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world!")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
3. Gevent
Gevent๋ ๊ทธ๋ฆฐ ์ค๋ ๋(green thread)๋ฅผ ์ฌ์ฉํ๋ ๋น๋๊ธฐ I/O ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๊ธฐ์กด์ ๋๊ธฐ ์ฝ๋๋ฅผ ๊ฑฐ์ ์์ ์์ด ๋น๋๊ธฐ๋ก ์ ํํ ์ ์์ผ๋ฉฐ, ๋จ์ํ ๋คํธ์ํฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ์์ฑํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฑ์๋์ ์ปค๋ฎค๋ํฐ ์ง์ ๋ฉด์์ ์ผ๋ถ ํ๊ณ๊ฐ ์์์ต๋๋ค.
- ๊ทธ๋ฆฐ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ํ๋ ฅ์ ๋ฉํฐํ์คํน
- ๋ธ๋กํน I/O ํจ์์ ๋น๋๊ธฐ ๋ณํ ์ง์
- ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ธ API
import gevent
from gevent import monkey
monkey.patch_all()
from gevent.pywsgi import WSGIServer
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, world!"
if __name__ == '__main__':
http_server = WSGIServer(('0.0.0.0', 5000), app)
http_server.serve_forever()
4. asyncio
Asyncio[1]๋ ํ์ด์ฌ 3.4์์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋์ ๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ํ๋ ์์ํฌ์ ๋๋ค. ์ฝ๋ฃจํด, ์ด๋ฒคํธ ๋ฃจํ, ํ์คํฌ, ๊ทธ๋ฆฌ๊ณ ๋ฏธ๋(future) ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ I/O๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ์ต์ ํ์ด์ฌ ์ํ๊ณ์ ์ ํตํฉ๋๋ฉฐ, ๋ค์ํ ๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ์ ๊ธฐ๋ฐ์ด ๋ฉ๋๋ค. ๋ง์ ์ต์ ๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ(aiohttp, Sanic, FastAPI ๋ฑ)๊ฐ asyncio๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ฐ๋์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๊ธฐ ๋ฒ์ ์์ ์ฑ๋ฅ๊ณผ ์ฌ์ฉ์ฑ ๋ฌธ์ ๋ก ์ธํด ํผ๋์ด ์์๊ณ , ์ฌ๋ฌ ๋น๋๊ธฐ ํ๋ ์์ํฌ๊ฐ ๊ฒฝ์ํ๋ ์ํฉ์ด ์ง์๋์์ต๋๋ค.
- ํ์ด์ฌ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ ๊ณต
- ์ฝ๋ฃจํด์ ์ฌ์ฉํ ๋ช ์์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ
- ๋ค์ํ ๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ ์ง์
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
# ๋ ๊ฐ์ ์ฝ๋ฃจํด์ ๋์์ ์คํํฉ๋๋ค.
await asyncio.gather(
say_after(1, 'hello'),
say_after(2, 'world')
)
print(f"finished at {time.strftime('%X')}")
# Python 3.7 ์ด์์์๋ asyncio.run()์ ์ฌ์ฉํ์ฌ main ์ฝ๋ฃจํด์ ์คํํ ์ ์์ต๋๋ค.
asyncio.run(main())
๊ฒฐ๋ก
ํ์ด์ฌ์ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ฐ๊ฐ ๊ณ ์ ํ ํน์ง๊ณผ ๊ฐ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. Twisted
๋ ๋ค์ํ ๋คํธ์ํฌ ํ๋กํ ์ฝ์ ์ง์ํ๋ ๋ณต์กํ ์ ํ๋ฆฌ์ผ์ด์
์ ์ ํฉํ๋ฉฐ, Tornado
๋ ๋์ ์ฑ๋ฅ์ ๋น๋๊ธฐ ์น ์๋ฒ๋ฅผ ์ ๊ณตํฉ๋๋ค. Gevent
๋ ๊ทธ๋ฆฐ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ์กด์ ๋๊ธฐ ์ฝ๋๋ฅผ ๋น๋๊ธฐ๋ก ์ฝ๊ฒ ์ ํํ ์ ์์ผ๋ฉฐ, asyncio
๋ ์ต์ ํ์ด์ฌ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ค์ํ ๋น๋๊ธฐ ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฉํฉ๋๋ค.
ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ๊ณผ ํ๊ฒฝ์ ๋ฐ๋ผ ์ ํฉํ ๋น๋๊ธฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ํํ์ฌ ์ฌ์ฉํ๋ฉด, ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ด์ ์ ๊ทน๋ํํ ์ ์์ต๋๋ค.