RabbitMQ

معماری RabbitMQ به صورت زیر است

Exchange چهار نوع دارد و دو نوع اصلی آن:

Fanout: در این حالت Exchange به routing key اهمیتی نمی دهد و تمامی پیام ها را به تمامی صف ها می فرستد.

Direct: در این حالت Exchange ها routing key ها را بررسی می کنند و پیامها را به صف های مرتبط می فرستند.

فرق دو کد زیر چیست؟

,

اولی پیام رو به همان کانکشن بر میگردونه دومی به با توجه به همان routing key که اینجا به نام group name هست می فرسته یعنی ممکنه به 100 نفر بفرسته

django channels sync async

تفاوت دو تکه کد زیر که از Django channels استفاده کرده است چیست؟

و

هر دو کد consumer هایی برای برقراری ارتباط websocket هستند. در اولی از ارتباط sync استفاده شده و در دومی از ارتباط async استفاده شده است.

در نتیجه:

در اولی:

اگر یک کانکشن برقرار شود، دیگر هیچ کانکشنی برقرار نمیشود تا کانکشن اولی بسته شود. چون کانکشن اول accept شده و هر کانکشن یک worker thread رو اشغال میکنه و تا زمانی که بسته نشه thread برای کانکشن بعدی باز نمیشه. این روش برای کارهای سریع مثل یه ارتباط با دیتابیس مناسب است اما برای یک ارتباط websocket که قرار است مدت زیادی باز بماند خوب نیست.

در دومی:

ارتباطات async است یعنی در واقع به آن گفته می شود که در قسمت await منتظر بمان تا I/O تکمیل شود اما در طول این انتظار ارتباطات دیگر می توانند برقرار شوند. در این حالت هر ارتباط به صورت یک task در event loop اجرا میشود. event loop ارتباطات دیگر را مدیریت میکند.

در واقع در حالت sync تسکها توسط worker ها انجام میشود و در حالت async تسک ها توسط event loop.

حالت sync مانند آشپزیست که هر قسمت غذا را کامل می پزد و بعد سراغ قسمت بعدی می رود اما حالت async چند ماهیتابه جلوی آشپز است که هر کدام را می چرخاند و سراغ بعدی می رود. این کار را event loop انجام می دهد که در پایتون در asyncio پیاده سازی شده است.

در دو consumer ای که نوشته شد هم داستان همین است. تا کانکشن اول بسته شود کانکشن بعدی باز نمی شود اما در حالت async این طور نیست و کانکشن اول در قسمت await وای میسه و event loop سراغ کانکشن های بعدی می رود.

کی از Message Queue استفاده میکنیم؟ وقتی که قرار باشد پیامی بین process ها یا consumer ها جابجا شوند. در واقع هر وقت توی django channels از channel layer بخایم استفاده کنیم باید از message q استفاده کنیم. در واقع channel layer همان message queue است.

annotate و عدم اعمال Index

این 2 کد را در نظر بگیرید:

و

با تبدیل اولی به دومی زمان این query از 450 میلی ثانیه به 45 میلی ثانیه کاهش پیدا کرد. چرا؟

دلیل این بود که فیلدهای این مدل همگی Index بودند اما این ایندکسها اعمال نمی شدند چونکه annotate باعث میشود که کل جدول اسکن شود و عملا ایندکسها بی فایده باشند بنابراین حداقل st=0 را به قبل از annotate انتقال دادیم و این باعث شد برای annotate که اتفاقا از WHERE استفاده میکند از ایندکس استفاده شود.

مقایسه دو تکه کد

تفاوت دو کد زیر چیست و کدام بهتر است؟

و

در کد اول اگر thumbnail توسط کاربر انتخاب نشود یک فایل از مسیر mag آپلود میشود. و هنگام پاک شدن آبجکت مربوطه، اگر این آبجکت دارای این فایل پیشفرض بود پاک نشود که البته در این کد مربوطه خود به خود پاک می شود. پس یک باگ وجود دارد. گذشته از این باگ اگر 1000 بار کاربر بدون thumbnail فایل آپلود کند 1000 فایل تکراری ذخیره میشود.

در ضمن اگر فایل بهر دلیلی پاک شود یا نام آن تغییر کند سیستم دچار مشکل میشود.

در کد دوم اما اگر کاربر فایلی انتخاب نکند هیچ فایل پیش فرضی آپلود نمیشود بنابراین فایل تکراری دیده نمی شود و فضا هدر نمی روند.

از طرفی یک فایل static پاک نشده و هرکجا یک سند thumbnail نداشته باشد با متد get_thumbnail_url این فایل نشان داده میشود و دیگر سیستم دچار باگهای ناخواسته نمی شود.

خروجی کد مصاحبه

خروجی کد زیر چیه؟

طبق حدثم:

ولی else چی میگه

خروجی:

یعنی اگه Exception اتفاق نیوفته else هم اتفاق میوفته. در هر حالتی finally اتفاق میوفته

سوال مصاحبه ارثبری

امروز توی یه مصاحبه سوال زیر مطرح شد و گفتن که خروجی برنامه چیه و من بعدا که تستش کردم سورپرایز شدم.

خروجی کد از قرار زیره:

بله سورپرایز شدیم. حالا برای اینکه بفهمیم چرا اینطور شد کد زیر رو اجرا میکنیم:

و خروجی کد:

خوب مشخص شد مساله چیه. توی ارثبری کلاس ها توی پایتون حتی اگه هیچی هم تغییر نکنه کلاس جدید به جای جدیدی از حافظه اشاره میکنه. در واقع کلاس پدر کپی میشه توی جای جدیدی از حافظه و کلاس فرزند یه pointer به جای جدیده. و در زمان اجرا کلاس هر تغییری هم بکنه به جای جدیدی نمیره که بنابراین آدرس حافظه کلاس در هیچ شرایطی تغییر نمیکنه.

اما متغیری که توی کلاس تعریف شده داستانش فرق میکنه. توی کلاس A پدر متغیر val به یه آدرس توی حافظه اشاره میکنه. کلاس B و C که فرزند هستن به همون آدرس حافظه اشاره مکنه. حالا وقتی B.val رو تغییر میدیم (از اونجایی که integer توی پایتون immutable هست) اون خونه حافظه تغییر نمیکنه بلکه یک خونه جدید با مقدار جدید ساخته میشه و B.val به اون اشاره میکنه. حالا باید خونه قبلی حافظه رو پاک کنه اما چون 2 تا pointer دیگه بهش وصله اونو پاک نمیکنه (Garbage collector وقتی اون خونه حافظه رو پاک میکنه که هیچ pointer ای به اون اشاره نکنه)

حالا داستان دوم. با این منطق اگر A.val رو تغییر بدیم باید C.val تغییر نکنه چون A.val به آدرس جدید اشاره میکنه ولی خانه قبلی پاک نمیشه چون هنوز C.val به خانه قبلی اشاره میکنه. اما مساله دیگه ای هم هست این جا از ارثبری استفاده کردیم و C فرزند A هست پس حالا که A.val به خانه جدیدی از حافظه اشاره میکنه این pointer رو توی فرزندانش هم عوض میکنه و بازم C.val و A.val به یک خانه جدید یکسان اشاره میکنن. ولی B.val دیگه این اتفاق براش نمیوفته چون از قبل به خونه دیگه ای اشاره میکنه (تغییر کرده) اگر پایتون این رو جوری دیگه پیاده سازی میکرد قطعا به مشکل میخوردیم.

واقعا سوال باحالی بود.

سوال مصاحبه

در ادامه یک سوال مصاحبه جالب از یک شرکت غیرایرانی رو میبینیم که زمان انجامش 45 دقیقه است.

کد زیر را کامل کنید. هدف این است که یک XML به صورت تکست به شما بدهند و شما یک object برگردانید که المانهای این XML در آن قابل فراخوانی باشند همانطور که در تابع main میبینید. (کد به صورت بازگشتی باشد)

کاربرد nested method در پایتون

کد زیر رو می تونید توی django.forms.fields.py ببینید. یه نکته جالب داره. متد split_url رو توی متد to_python تعریف کرده:

سوال اینجاست که چرا باید یه متد رو توی متدی دیگه تعریف کرد؟ کاربردش چیه؟ مزایاش چیه؟ و چجوری باید صدا زد اونها رو:

دلیل استفاده از این روش توی OOP گفته شده که اگر قرار باشه که یک کار رو چندین بار توی یک متد انجام داد باید اون رو یک به صورت یک تابع بنویسیم تا اینجا که واضحه (دلیل تابع). حالا فرض کنیم بخایم از یک تابع فقط توی یک متد از یک کلاس استفاده کنیم، یعنی اصلا حتی به متدهای دیگه همون کلاس ربطی نداره. اون وقته که منطقی میشه از این روش استفاده کرد و فقط هم باید توی همون متد to_python صدا زده بشه.

مزایاش که مشخصه، اگه کدی لازم نباشه به scope های دیگه نشون داده نمیشه و مزایای دیگه…

F() expression توی جنگو

تفاوت دو کد زیر چیست؟

استفاده از F() expression توی کد جنگوی بالا این امکان رو میده که تغییر فیلد و increment کردنش سمت دیتابیس آماده انجام بشه بجای اینکه پایتون یک واحد بهش اضافه کنه. یعنی یک query میره سمت دیتابیس و مقدار فیلد هرچی هست همونجا یه واحد اضافه میشه. اینجوری دیگه لازم نیست یک بار از دیتابیس بگیره و اضافه کنه و آپدیت شده رو بفرسته سمت دیتابیس و دو query اجرا کنه. اما برای اینکه مقدار آپدیت شده سمت دیتابیس را داشته باشیم: