آشنایی با Event Loop در NodeJS


برای هر برنامه نویسی مهم است که بهترین ساختار و البته پلتفرم را برای توسعه انتخاب کند، اما از همه ای این ها مهمتر استفاده از آن برای توسعه کارآمد و سریع راه حل ها می باشد.باید تصمیم بگیریم که نیاز یک محصول چیست و با توجه به آن یک تصمیم عاقلانه را برای انتخاب بهترین ساختار برای فرانت-اند و بک-اند بگیریم و درنهایت آن را به واقعیت تبدیل کنیم.موضوع درباره رقابت بین ساختارهای مختلف نیست و بیشتر توسعه دهندگان باید سعی کنند ساختاری را برای توسعه انتخاب کنند و یادبگیرند که همانطور که در حال حاضر مورد استفاده قرار می گیرند آینده ای هم داشته باشند که بتوان از آن ها استفاده نمود.
امروز می خواهیم یک از بهترین ویژگی های نود جی اس یعنی Event Loop را مورد بررسی قرار دهیم از طرفی چگونه نود جی اس فرآیندها را بدون استفاده از چند ترد (Multi-threading) اجرا و مدیریت می کند.
نود جی اس از یک ترد برای اجرای فرآیندها استفاده می کند!؟
مسلما تا این لحظه درباره تردها و نحوه اجرای نود جی اس تنها با استفاده از یکی از اینها شنیده اید در کنار همه این مسائل حتمی درباره سایر تکنولوژی های سمت سرور مانند php, ASP.NET, Ruby, Java که از چندین ترد (multi-thread) برای اجرای فرآیندها استفاده می کنند شنیده اید به طوری که به ازای درخواست هر کاربر یک ترد برای آن در نظر گرفته می شود.اما در نود جی اس همین فرآیندها از طریق یک ترد (single-thread) همراه با اشتراک گذاری منابع به وسیله event ها انجام می شود.بنابراین تمام برنامه های توسعه داده شده با نود جی اس از مکانیزم single-thread event loop برای مدیریت درخواست های چندگانه کاربران استفاده می کنند.در اصل event loop ها روی یک ترد و اکثر فرایندهای I/O به دلیل طراحی آسنکرون (Asyanchronous) و البته مسدود نشونده (non-blocking) روی یک ترد مجزا اجرا می شود و در نهایت خود را با event loop ها تطبیق می دهند.
فرآیندهای نود جی اس در قالب یک ترد چکونه اجرا می شوند :
یک فرآیند با استفاده از نود جی اس به صورت آسنکرون (Asynchronous) و با استفاده از event loop ها اجرا می شود.
نمونه کد :
1 2 3 4 5 6 7 8 9 10 11 |
var sockets = require('websocket.io'),httpServer = sockets.listen(4000); httpServer.on('onConnection', function (socket) { console.log('connected……'); httpServer.send('Web socket connected.'); httpServer.on('message', function (data) { console.log('message received:', data); }); httpServer.on('close', function () { console.log('socket closed!'); }); }); |
با توجه به کد بالا زمانی که دستور sockets.listen(4000) اجرا می شود سرور وب سوکت بر روی یک ترد بااستفاده از event loop ایجاد می شود و دائما به پورت 4000 گوش می دهد.زمانی که یک کاربر وب و یا اپلیکیشن به سرور متصل می شود رویداد onConnect اجرا شده و سایر فرآیندهای حلقه در پس زمینه اجرا می شود و اکنون آماده دریافت سایر درخواست ها می باشد و این می تواند اصلی ترین تفاوت میان وب سرورهای مبتنی بر nodejs و IIS/Apache باشد به طوری که نود جی اس برای هر درخواست اتصال یک ترد ایجاد نمی کند و این درحالی است که تمام در خواست ها در یک ترد دریافت شده و با استفاده از ساختارهایی در پس زمینه توسط فرآیندهای دیگر اجرا می شود. تمامی این فرآیندها در پس زمینه توسط کتابخانه libuv انجام می شود مکانیزم این کتابخانه بگونه ایست که صف ها و فرآیندهای رویداد محور آسنکرون را که در حال حاضر قدرتمند ترین هسته ها هم آن را به صورت multi thread اجرا می کنند را در پس زمینه فرآیندها می تواند به راحتی اجرا کند. زمانی که یک فرآیند کامل می شود هسته این کتابخانه به نود جی اس می گوید که پاسخ مناسب را با قرار دادن ان در پشته و در نهایت اجرای آن دهد.
در مجموع Event Loop ها باعث می شوند تا نود جی اس فرآیندها را به صورت مسدود نشونده (non blocking) اجرا کند و از طرفی جاوااسکریپت تک تردی است و این کار از طریق فرآیندهای offload که به هسته واگذار می کند در هر زمان اجرا می کند. اجازه بدین برای اینکه بیشتر با رویدادها آشنا شوید توضیح بیشتری را ارائه دهیم، مفهوم تک ترد (single-thread) در نود جی اس یعنی مدیریت آسنکرون درخواست های اتصال که از طریق این ساختار داده می شود. نود یک مخزن ترد دارد و اگر تمام این فرآیندها را در نهایت به هسته واگذار می کند پس چه نیازی به ترد است ؟به این دلیل که هسته نمی تواند تمامی فرآیندهای آسنکرون را مدیریت کند.به همین دلیل نود در برخی موارد یک ترد را در مدت زمان اجرای یک فرآیند مسدود می کند تا حلقه رویداد بتواند بدون مسدود شدن به کار خود ادامه دهد.
به نمودار زیر دقت کنید به طوری که نحوه اجرای فرآیندها در نود جی اس رو به سادگی شرح می دهد :
هر یک از باکس های نمودار بالا یک فاز مجزا در حلقه رویداد می باشد.
Timers : در این فاز فرآیند callback با توجه به یک برنامه زمانبندی شده توسط توابع ()setTimeOut و ()setInterval انجام می شود.هر یک از اینها یک آستانه را مشخص می کنند بنابراین یک callback دقیقا بعد از مدت زمانی که مشخص شده اجرا خواهد شد.
I/O callbacks : تمام فرآیندهای callback را تقریبا اجرا می کند بجز آنهایی که اجرای آنها به اتمام رسیده، توابعی از طریق توابع بالا برای اجرای آنها بازه زمانی در نظر گرفته شده است و اینکه برای اجرای آنها از تابع ()setImmediate استفاده شده است.
Idle, prepare : بعنوان یکی از توابع داخلی فرآیندها را کنترل می کند.
Poll : رویدادهای I/O جدید را بازیابی می کند و گره ممکن است در صورتی که شرایط در این بخش مناسب باشد مسدود گردد.
Check : تابع ()setImmediate در این بخش فرآخوانی می شود.
Close callback : اتمام فرآیندها در بخش انجام می شود مثل :
1 |
socket.io(‘close’, …) |
تمامی این مراحل با توجه به ساختار FIFO مشابه مکانیزم پشته ها برای مدریت فرآیندهای Callback عمل می کند.هر مرحله منحصر به فرد است و به طور کلی زمانی که یک رویداد وارد یک فاز می شود باید عملیات های خاص و مختص به آن مرحله را انجام دهد پس تمامی فرآیندها و البته callbackها در یک صف برای اجرا قرار می گیرند تا زمانی که یک صف تمام شود و یا تعداد زیادی از Callback ها را اجرا شوند.زمانی که صف تمام شود و یا به یک محدودیت فرآخوانی برسد رویداد کار خود را با ورود به فاز بعد ادامه خواهد داد و در نهایت این جریان تا اتام کامل تمام فرآیندها ادامه خواهد داشت.
دیدگاهتان را بنویسید