تورنادو 2
راهنمای مبتدیان برای Python Tornado
وب اکنون مکان بزرگی است. ما نیاز به پشتیبانی از هزاران مشتری در یک زمان داریم، و در اینجا تورنادو به میان می آید. تورنادو یک چارچوب وب پایتون و کتابخانه شبکه نا همزمان است که در اصل در FriendFreed توسعه یافته است.
تورنادو از io شبکه غیر مسدود کننده استفاده می کند. به همین دلیل، می تواند هزاران اتصال فعال سرور را مدیریت کند. این یک نجات دهنده برای برنامه هایی است که در آن نظرسنجی طولانی و تعداد زیادی اتصال فعال حفظ می شود.
تورنادو مانند اکثر چارچوب های پایتون نیست. این بر اساس WSGI نیست، در حالی که از برخی از ویژگی های WSGI را با استفاده از ماژول `tornado.wsgi` پشتیبانی می کند. از طراحی حلقه رویداد استفاده می کند که اجرای درخواست تورنادو را سریعتر می کند.
برنامه همگام چیست؟
یک تابع که مسدود می کند، محاسبات خود را انجام می دهد و پس از انجام برمی گرداند. یک تابع ممکن است به دلایل زیادی مسدود شود: ورودی / خروجی شبکه، ورودی / خروجی دیسک، mutexes و غیره.
عملکرد برنامه بستگی به این دارد که برنامه چقدر کارآمد از چرخه های CPU استفاده می کند، به همین دلیل مسدود کردن بیانیه ها / تماس ها باید جدی گرفته شود. توابع درهم سازی (hashing) رمز عبور مانند bcrypt را در نظر بگیرید که از نظر طراحی از صد ها میلی ثانیه زمان CPU استفاده می کنند که بسیار بیشتر از یک شبکه معمولی یا دسترسی به دیسک است. از آنجایی که CPU بیکار نیست، نیازی به رفتن به توابع نا همزمان نیست.
یک تابع می تواند در یکی مسدود کننده و در برخی دیگر غیر مسدود کننده باشد. در زمینه تورنادو، ما به طور کلی مسدود کردن را به دلیل ورودی / خروجی شبکه و دیسک در نظر می گیریم، اگرچه همه انواع مسدود کردن باید به حداقل برسد.
برنامه سنکرون (Asynchronous) چیست؟
1) معماری تک رشته ای:
به این معنی که نمی تواند وظایف محاسباتی محور را به صورت موازی انجام دهد.
2) همزمانی I / O:
این می تواند وظایف I/O را به سیستم عامل واگذار کند و برای رسیدن به موازی سازی به کار بعدی ادامه دهد.
3) epoll / kqueue:
تاکید بر زیر ساختار مربوط به سیستم که به برنامه اجازه می دهد رویداد ها را در یک توصیفگر فایل یا وظایف خاص I / O دریافت کند.
4) حلقه رویداد:
از epoll یا kqueue برای بررسی اینکه آیا رویدادی رخ داده است یا خیر، استفاده می کند و بازخوانی را اجرا می کند که منتظر آن رویداد های شبکه است.
چارچوب وب سنکرون یا نا همزمان در مقابل چارچوب وب همگام:
در مدل سنکرون، هر درخواست یا کار به thread یا routing منتقل می شود و با اتمام آن، نتیجه به تماس گیرنده تحویل داده می شود. در اینجا، مدیریت کار ها آسان است، اما ایجاد رشته های جدید هزینه زیادی دارد.
از سوی دیگر، در چارچوب نا همزمان، مانند Node.js ، یک مدل رشته ای وجود دارد، بنابراین سربار بسیار کمتری دارد، اما پیچیدگی دارد.
بیایید تصور کنیم که هزاران درخواست ارسال می شوند و یک سرور از حلقه رویداد و تماس برگشتی استفاده می کند. اکنون، تا زمانی که درخواست پردازش نشود، باید به طور موثر وضعیت آن درخواست را ذخیره و مدیریت کند تا نتیجه برگشت به تماس را به مشتری واقعی نگاشت کند.
Node.js در مقابل تورنادو
بیشتر این نکته های مقایسه مربوط به زبان برنامه نویسی واقعی می باشد و نه چارچوب:
- js یک مزیت بزرگ دارد که تمام کتابخانه های آن نا همزمان هستند. در پایتون، بسته های موجود زیادی وجود دارد، اما تعداد بسیار کمی از آنها نا همزمان هستند
- از آن جایی که js زمان اجرا جاوا اسکریپت است و ما میتوانیم از JS برای هر دو قسمت جلوگاه و پشتگاه استفاده کنیم، توسعه دهندگان می توانند تنها یک پایگاه کد نگه دارند و کتابخانه سودمند یکسانی را به اشتراک بگذارند.
- موتور V8 گوگل js را سریعتر از تورنادو می سازد. اما بسیاری از کتابخانه های پایتون به زبان C نوشته شده اند و می توانند جایگزین های سریع تری باشند.
یک مثال ساده از ‘Hello World’
1 import tornado.ioloop
2 import tornado.web
3
4 class MainHandler(tornado.web.RequestHandler):
5 def get(self):
6 self.write(“Hello, world”)
7
8 def make_app():
9 return tornado.web.Application([
10 (r”/”, MainHandler),
توجه: این مثال از هیچ ویژگی نا همزمانی استفاده نمی کند.
با استفاده از ماژول AsyncHTTPClient، می توانیم تماس REST را به صورت نا همزمان انجام دهیم.
1 from tornado.httpclient import AsyncHTTPClient
2 from tornado import gen
3
4 @gen.coroutine
5 def async_fetch_gen(url):
6 http_client = AsyncHTTPClient()
7 response = yield http_client.fetch(url)
8 raise gen.Return(response.body)
همان طور که می بینید، `yield http_client.fetch(url)` به عنوان یک کوروتین اجرا می شود.
مثالی پیچیده از نا همزمانی تورنادو
لطفا به کنترل کننده درخواست ناهمزمان نگاهی بیندازید.
WebSockets با استفاده از تورنادو:
تورنادو بسته ای را برای WebSockets ساخته است که می تواند به راحتی با کوروتین ها برای دستیابی به همزمانی استفاده شود، در اینجا یک مثال آورده ایم:
1 import logging
2 import tornado.escape
3 import tornado.ioloop
4 import tornado.options
5 import tornado.web
6 import tornado.websocket
7 from tornado.options import define, options
8 from tornado.httpserver import HTTPServer
9
10 define(“port”, default=8888, help=”run on the given port”, type=int)
11
12
13 # queue_size = 1
14 # producer_num_items = 5
15 # q = queues.Queue(queue_size)
16
17 def isPrime(num):
18 “””
19 Simple worker but mostly IO/network call
20 “””
21 if num > 1:
22 for i in range(2, num // 2):
23 if (num % i) == 0:
24 return (“is not a prime number”)
25 else:
26 return(“is a prime number”)
27 else:
28 return (“is not a prime number”)
29
30 class Application(tornado.web.Application):
31 def __init__(self):
32 handlers = [(r”/chatsocket”, TornadoWebSocket)]
33 super(Application, self).__init__(handlers)
34
35 class TornadoWebSocket(tornado.websocket.WebSocketHandler):
36 clients = set()
37
38 # enable cross domain origin
39 def check_origin(self, origin):
40 return True
41
42 def open(self):
43 TornadoWebSocket.clients.add(self)
می توان از یک برنامه مشتری WebSocket برای اتصال به سرور استفاده کرد، پیام می تواند هر عدد صحیح باشد. پس از پردازش، مشتری نتیجه را دریافت می کند که عدد صحیح اول باشد یا خیر.
در اینجا یک مثال دیگر از ویژگی های غیر همزمان واقعی تورنادو آورده شده است. بسیاری آن را شبیه به گوروتین و کانال های Golang می دانند.
در این مثال، میتوانیم عامل(های) را راه اندازی کنیم و آنها به ‘tornado.queue’ گوش خواهند داد. این صف نا همزمان است و بسیار شبیه به بسته asyncio می باشد.
1 # Example 1
2 from tornado import gen, queues
3 from tornado.ioloop import IOLoop
4
5 @gen.coroutine
6 def consumer(queue, num_expected):
7 for _ in range(num_expected):
8 # heavy I/O or network task
9 print(‘got: %s’ % (yield queue.get()))
10
11
12 @gen.coroutine
13 def producer(queue, num_items):
14 for i in range(num_items):
15 print(‘putting %s’ % i)
16 yield queue.put(i)
17
18 @gen.coroutine
19 def main():
20 “””
دیدگاهتان را بنویسید