خیلی وقتها به اسم بالا بردنِ بهرهوری، روزها وقتمون رو صرف پیدا کردن بهترین تم ادیتور، کانفیگ کردن دقیق
• محیط کارت باید "به اندازه کافی خوب" باشه، نه بینقص.
• اگه کانفیگ کردنِ یه ابزار بیشتر از ارزشی که تو طول هفته برات خلق میکنه زمان میبره، درجا رهاش کن.
• یه محیط ساده و خستهکننده که توش روزی هزار خط کد بزنی، شرف داره به یه سیستم به شدت شخصیسازی شده که فقط به دردِ اسکرینشات گرفتن و
از ابزارها برای خلق کردن استفاده کنید، نه اینکه خود ابزارها بشن پروژه اصلیتون.
👤• #FromFarshad@Melfex
Zsh، یا شخصیسازی ریزبهریز محیط دسکتاپ میکنیم. ذهن ما این کارها رو به عنوان "کار مفید" ثبت میکنه، در صورتی که در واقعیت داریم از انجام دیپوورک و کد زدن واقعی فرار میکنیم. یادمون باشه؛ وسواس روی ابزارها، توهمِ پیشرفت میده. • محیط کارت باید "به اندازه کافی خوب" باشه، نه بینقص.
• اگه کانفیگ کردنِ یه ابزار بیشتر از ارزشی که تو طول هفته برات خلق میکنه زمان میبره، درجا رهاش کن.
• یه محیط ساده و خستهکننده که توش روزی هزار خط کد بزنی، شرف داره به یه سیستم به شدت شخصیسازی شده که فقط به دردِ اسکرینشات گرفتن و
Neofetch میخوره!از ابزارها برای خلق کردن استفاده کنید، نه اینکه خود ابزارها بشن پروژه اصلیتون.
👤• #FromFarshad@Melfex
👏3❤🔥1💋1🦄1
اگه شما هم موقع توسعه فرانتاَند یا مینیآپهای تلگرام، از ستاپ کردن سرورهای فیک، نوشتن ماکهای طولانی توی کد یا قطعی اینترنت و بالا نیومدن اِیپِیآیهای تست خسته شدید، وقتشه با
ماکون یک ابزار فوقالعاده سبک، اوپنسورس و کاملاً آفلاین برای شبیهسازی اِیپِیآیهای
• راهاندازی در چند ثانیه: بدون نیاز به ساخت اکانت، کلاد یا کثیفکاریهای مرسوم؛ خیلی راحت میتونید چندتا روتِ فیک با ریسپانسهای جیسون دلخواه بسازید و به عنوان لوکالهاست به فرانت یا ابزار تستون متصلش کنید.
• شبیهسازی محیط واقعی: میتونید برای روتها شرط بذارید؛ مثلاً اگه فلان هدر توی ریکوئست بود ریسپانس ۲۰۰ برگرده و اگه نبود ارور ۴۰۱ یا ۴۰۳ برگردونده بشه. حتی میتونید روی روتها دِلِی داینامیک ست کنید تا رفتار نتورک تو شرایط واقعی و اینترنت ضعیف رو تست کنید.
• محیط کاملاً گیتفرندلی: تمام محیطها و روتهایی که میسازید توی یک فایل جیسون ساده ذخیره میشن.
📦 github.com/mockoon/mockoon
⌨• #DevEdu@Melfex
Mockoon آشنا بشید.ماکون یک ابزار فوقالعاده سبک، اوپنسورس و کاملاً آفلاین برای شبیهسازی اِیپِیآیهای
REST هست که پروسه توسعه و تست رو به شدت سریع میکنه:• راهاندازی در چند ثانیه: بدون نیاز به ساخت اکانت، کلاد یا کثیفکاریهای مرسوم؛ خیلی راحت میتونید چندتا روتِ فیک با ریسپانسهای جیسون دلخواه بسازید و به عنوان لوکالهاست به فرانت یا ابزار تستون متصلش کنید.
• شبیهسازی محیط واقعی: میتونید برای روتها شرط بذارید؛ مثلاً اگه فلان هدر توی ریکوئست بود ریسپانس ۲۰۰ برگرده و اگه نبود ارور ۴۰۱ یا ۴۰۳ برگردونده بشه. حتی میتونید روی روتها دِلِی داینامیک ست کنید تا رفتار نتورک تو شرایط واقعی و اینترنت ضعیف رو تست کنید.
• محیط کاملاً گیتفرندلی: تمام محیطها و روتهایی که میسازید توی یک فایل جیسون ساده ذخیره میشن.
📦 github.com/mockoon/mockoon
⌨• #DevEdu@Melfex
❤🔥4⚡1💅1
امروز سعی داشتم ی سیستم واسه دیلیت کردن مسیجها با ی دیلی مشخص پیاده سازی کنم. چیزی که توی وهله اول به فکرم رسید، استفاده ترکیبی از
پایتون ماژولی تحت عنوان
وقتی ی تسک جدید به این صف اضافه میکنیم، نیازی به سورت کل لیست با هزینهی پردازشی زیاد نیست، بلکه عنصر جدید با پیچیدگی زمانی فوقالعاده پایین داخل جای درست خودش مینشینه.
استفاده عملی از این ماژول رو میتونید توی آخرین کامیت این ریپو ببینید 👀؛
📦 github.com/Melfex/telegram-msg-bridge/blob/main/util/scheduler.py
⌨• #DevEdu@Melfex | #TelegramBot
asyncio.sleep و asyncio.create_task بود، ولی خب خیلی مشکل داشت، واسه همین با چندتا سرچ به ماژول heapq رسیدم.پایتون ماژولی تحت عنوان
heapq داره که ساختمان دادهی Min-Heap رو پیاده سازی میکنه. به زبون ساده، داخل ی آرایهی Min-Heap، سیستم این تضمین رو میده که کوچیکترین عنصر ( توی معماری مد نظر من، نزدیکترین تایم برای حذف کردن پیام ) همیشه داخل ایندکس صفر وجود داره. وقتی ی تسک جدید به این صف اضافه میکنیم، نیازی به سورت کل لیست با هزینهی پردازشی زیاد نیست، بلکه عنصر جدید با پیچیدگی زمانی فوقالعاده پایین داخل جای درست خودش مینشینه.
استفاده عملی از این ماژول رو میتونید توی آخرین کامیت این ریپو ببینید 👀؛
📦 github.com/Melfex/telegram-msg-bridge/blob/main/util/scheduler.py
⌨• #DevEdu@Melfex | #TelegramBot
⚡2🔥1💘1
شاید یکی از بزرگترین تلههایی که ما برنامهنویسها توش میافتیم، سندروم « Shiny Object Syndrome » باشه.
روال کار اینجوریه: داری روی ی پروژه با پایتون کار میکنی، یهو ی مقاله میخونی که "
تکنولوژیها و ابزارهای جدید فقط "ابزار" هستن، نه هدف نهایی. ارزش واقعی تو بازار کار و مهندسی نرمافزار، توانایی "حل مسئله" و "تمام کردنِ" پروژههاست، نه دونستن سینتکس ده تا زبان مختلف.
پیشنهاد همون قانون ٨٠/٢٠ هست؛ ی زبان یا فریمورک رو به عنوان چکش اصلیت انتخاب کن و انقدر باهاش میخ بکوب تا استادش بشی. بقیه چیزها رو فقط در حد نیاز و برای رفع کنجکاوی بخون.
البته این به معنی نادیده گرفتن تکنولوژیهای جدید نیست. ابزارهای موفق معمولاً برای حل ی مشکل مشخص به وجود میان، نه اینکه قراره جایگزین همهچیز بشن.
👤• #FromFarshad@Melfex
روال کار اینجوریه: داری روی ی پروژه با پایتون کار میکنی، یهو ی مقاله میخونی که "
Rust آینده رو تسخیر میکنه!". پروژه رو نصفه ول میکنی و میری سراغ سینتکس راست. هفته بعد ی ویدیو میبینی درباره قابلیتهای جدید Next.js، دوباره شیفت میکنی سمت فرانتاند. نتیجه؟! دهها پروژه نصفهکاره، ی گیتهاب پر از ریپوهای Hello World و دانشی که مثل ی اقیانوس به عمق یک سانتیمتره. تکنولوژیها و ابزارهای جدید فقط "ابزار" هستن، نه هدف نهایی. ارزش واقعی تو بازار کار و مهندسی نرمافزار، توانایی "حل مسئله" و "تمام کردنِ" پروژههاست، نه دونستن سینتکس ده تا زبان مختلف.
پیشنهاد همون قانون ٨٠/٢٠ هست؛ ی زبان یا فریمورک رو به عنوان چکش اصلیت انتخاب کن و انقدر باهاش میخ بکوب تا استادش بشی. بقیه چیزها رو فقط در حد نیاز و برای رفع کنجکاوی بخون.
البته این به معنی نادیده گرفتن تکنولوژیهای جدید نیست. ابزارهای موفق معمولاً برای حل ی مشکل مشخص به وجود میان، نه اینکه قراره جایگزین همهچیز بشن.
👤• #FromFarshad@Melfex
❤3🔥2💘2👍1
اگه شما هم از کندی
• دیتای تو، روی سیستم تو؛ ابسیدین کاملاً آفلاینه. هیچ کلاد یا دیتابیس قفلشدهای در کار نیست. کل نوتهای شما صرفاً ی سری فایل متنی ساده با فرمت
• گیتفرندلی تا مغز استخون؛ چون فایلها متنی هستن، خیلی راحت میتونید پوشه نوتهاتون رو با
• گراف ویو؛ ابسیدین بهتون اجازه میده نوتهاتون رو به هم لینک بدید و در نهایت ی گراف بصری خفن از ارتباط ایدهها و چیزهایی که یاد گرفتید بهتون میده.
📦 obsidian.md
⌨• #DevEdu@Melfex
Notion، آنلاین بودن اجباریش، یا پخش و پلا شدن نوتهاتون تو اپهای مختلف خسته شدید، ابسیدین دقیقاً همون چیزیه که بهش نیاز دارید:• دیتای تو، روی سیستم تو؛ ابسیدین کاملاً آفلاینه. هیچ کلاد یا دیتابیس قفلشدهای در کار نیست. کل نوتهای شما صرفاً ی سری فایل متنی ساده با فرمت
md. هستن که روی هارد خودتون ذخیره میشن.• گیتفرندلی تا مغز استخون؛ چون فایلها متنی هستن، خیلی راحت میتونید پوشه نوتهاتون رو با
Git مدیریت کنید، کامیت بزنید و روی گیتهاب پرایوتتون پوش کنید.• گراف ویو؛ ابسیدین بهتون اجازه میده نوتهاتون رو به هم لینک بدید و در نهایت ی گراف بصری خفن از ارتباط ایدهها و چیزهایی که یاد گرفتید بهتون میده.
📦 obsidian.md
⌨• #DevEdu@Melfex
❤2👍2🍓2❤🔥1
SAMAN
یه چیزشم هست برای مدیریت نکردن پیام ها در دقیقه و ثانیس
همین الانم جفت رباتام این مشکل دارن
طرف میاد اینترنت خاموش میکنه بعدش کلی میزنه رو لینکا
اینترنت که روشن میکنه کلی قسمت میخواد براش بره اما به محدودیت پیام در ثانیه میخوره تا چند دقیقه قفل میشه
حالا همینو اگه با یه یوزربات بزنن که دیگه رسماً خاموشی مطلق 🫠🫠🫠🫠
همین الانم جفت رباتام این مشکل دارن
طرف میاد اینترنت خاموش میکنه بعدش کلی میزنه رو لینکا
اینترنت که روشن میکنه کلی قسمت میخواد براش بره اما به محدودیت پیام در ثانیه میخوره تا چند دقیقه قفل میشه
حالا همینو اگه با یه یوزربات بزنن که دیگه رسماً خاموشی مطلق 🫠🫠🫠🫠
امروز یکی از بچهها یه چالش بهشدت آشنا رو مطرح کرد.
از لحاظ معماری و پروتکل تلگرام دقیقا چه اتفاقی داره میافته؟! وقتی کاربر آفلاینه و روی باتنها یا لینکها پشت سر هم کلیک میکنه، کلاینت تلگرام معمولاً این ریکوئستها رو تا زمان برقراری اتصال نگه میداره. به محض وصل شدن اینترنت، این ریکوئستها بهصورت
اگه سیستم شما هیچ شیلدی برای این سناریو نداشته باشه، بات سعی میکنه به همهی این ریکوئستها پاسخ بده و بوم! خیلی سریع به
برای فیکس کردن اصولی این چالش، راهحل توی پیادهسازی یه
من دقیقاً برای هندل کردن همین
سناریوی این میدلور به این شکله که فرکانس پیامهای هر کاربر رو داخل یه
سورسکد این میدلور و استراکچرش رو میتونید از ریپوی زیر بخونید 👀؛
📦 github.com/Melfex/telegram-msg-bridge/blob/main/middleware/throttling.py
⌨• #DevEdu@Melfex | #TelegramBot
از لحاظ معماری و پروتکل تلگرام دقیقا چه اتفاقی داره میافته؟! وقتی کاربر آفلاینه و روی باتنها یا لینکها پشت سر هم کلیک میکنه، کلاینت تلگرام معمولاً این ریکوئستها رو تا زمان برقراری اتصال نگه میداره. به محض وصل شدن اینترنت، این ریکوئستها بهصورت
Burst پشت سر هم ارسال میشن و سرور تلگرام هم اونها رو با سرعت زیاد، از طریق وبهوک یا پولینگ، به سمت بات شما هدایت میکنه.اگه سیستم شما هیچ شیلدی برای این سناریو نداشته باشه، بات سعی میکنه به همهی این ریکوئستها پاسخ بده و بوم! خیلی سریع به
Rate Limit تلگرام برخورد میکنید و ارور معروف FloodWait ظاهر میشه. نتیجه؟! بخشی از ارسال پیامهای بات برای مدتی متوقف یا کند میشن و تجربهی کاربری بههم میریزه. حالا به قولا اگه پای یه یوزربات هم وسط باشه که عمدا این سناریو رو تکرار کنه، فشار واردشده روی سرور و بیزینسلاجیک میتونه واقعا دردسرساز بشه.برای فیکس کردن اصولی این چالش، راهحل توی پیادهسازی یه
Rate Limiter توی لایهی ورودی خلاصه میشه. ما نباید اجازه بدیم ریکوئستهای اسپم اصلا رنگِ بیزینسلاجیک، دیتابیس یا APIهای پروژه رو ببینن. خیلیها سریع میرن سراغ ردیس، ولی برای پروژهها و باتهایی که معماری Single-Node دارن، درگیر شدن با Network I/O و ردیس همیشه انتخاب بهینهای نیست و میتونه فقط یه Overhead اضافه باشه.من دقیقاً برای هندل کردن همین
Edge Case، توی لایهی بیس پروژهی Telegram-MSG-Bridge یه میدلور آنتیاسپم نوشتم که فعلاً برای Message پیادهسازی شده، اما بهراحتی میشه CallbackQuery رو هم بهش اضافه کرد. این میدلور بجای ردیس از ماژول فوقسریع cachebox و TTLCache استفاده میکنه. ( با تشکر از علی بابت این ماژول محشرش 🤍 )سناریوی این میدلور به این شکله که فرکانس پیامهای هر کاربر رو داخل یه
Window ( بازهی زمانی مشخص ) مانیتور میکنه. اگه کاربر از Threshold ( آستانهی مجاز ) عبور کنه، برای مدت مشخصی بلاک میشه. نکتهی کلفت و پرفورمنسی داستان دقیقا اینجاست؛ ریکوئستهای رگباری و پشتسرهم بعدی همونجا داخل میدلور بهصورت سایلنتدراپ حذف میشن ( فقط با یه "return None" ساده، توی کسری از میلیثانیه ) و اصلا به هنلدرهای اصلی بات، بیزینسلاجیک یا دیتابیس نمیرسن. در نتیجه هم فشار روی سرور کم میشه، هم از برخورد غیرضروری با Rate Limit تلگرام تا حد زیادی جلوگیری میکنید.سورسکد این میدلور و استراکچرش رو میتونید از ریپوی زیر بخونید 👀؛
📦 github.com/Melfex/telegram-msg-bridge/blob/main/middleware/throttling.py
⌨• #DevEdu@Melfex | #TelegramBot
🔥5👏1 1 1
کمال گرای مضطرب.pdf
25.5 MB
خیلی وقتها به اسم «ارائه بهترین کیفیت»، روزها و هفتهها وقتمون رو صرف این میکنیم که همهچیز بینقص باشه؛ از ویدیوهای تولید محتوا گرفته تا ریزترین جزئیات پروژهها و کارهای روزمره. ذهن ما این وسواس رو به عنوان «استاندارد بالا» توجیه میکنه، در صورتی که در واقعیت فقط داریم از شروع کردن فرار میکنیم و به شدت درگیر اهمالکاری میشیم.
این کتاب دقیقا دست میذاره روی همون نقطه کوری که باعث میشه کارها رو به تعویق بندازیم؛ جایی که ترس از کامل نبودن، ما رو فلج میکنه.
اگه شما هم درگیر تلهی کمالگرایی هستید، ایدههای زیادی تو سرتونه اما موقع اجرا متوقف میشید و مدام کارها رو عقب میندازید، خوندنش رو به شدت تجویز میکنم.
📚• #FReads@Melfex | #کمالگرای_مضطرب
©• @soufi_learn
این کتاب دقیقا دست میذاره روی همون نقطه کوری که باعث میشه کارها رو به تعویق بندازیم؛ جایی که ترس از کامل نبودن، ما رو فلج میکنه.
اگه شما هم درگیر تلهی کمالگرایی هستید، ایدههای زیادی تو سرتونه اما موقع اجرا متوقف میشید و مدام کارها رو عقب میندازید، خوندنش رو به شدت تجویز میکنم.
📚• #FReads@Melfex | #کمالگرای_مضطرب
©• @soufi_learn
❤🔥3🔥1
اگه برای توسعهی بکند یا هندل کردن وبهوکهای بات تلگرامتون از فریمورکهای مدرنی مثل
وقتشه با
گرانیان یه سرور
• پرفورمنس چشمگیر؛ توی خیلی از بنچمارکها، گرانیان توی هندل کردن ریکوئستهای همزمان عملکرد بهتری نسبت به
• پشتیبانی از
• مهاجرت ساده؛ اگه پروژهتون بر پایهی
اگه پروژهتون زیر لود بالاست یا صرفا دوست دارید ابزارهای جدید اکوسیستم پایتون رو امتحان کنید، گرانیان قطعا ارزش تست کردن رو داره. البته هیچ بنچمارکی جای تست روی پروژهی واقعی خودتون رو نمیگیره؛ پس قبل از مهاجرت، حتماً عملکردش رو روی
📦 github.com/emmett-framework/granian
⌨• #DevEdu@Melfex
FastAPI استفاده میکنید، احتمالاً انتخاب همیشگیتون برای ران کردن سرور، Uvicorn بوده. یوویکورن فوقالعادهست؛ اما اگه بهتون بگم یه سرور ASGI دیگه هست که توی خیلی از سناریوها عملکرد بهتری از خودش نشون داده، چی؟! وقتشه با
Granian آشنا بشید.گرانیان یه سرور
HTTP برای پایتونه که از ASGI، WSGI و RSGI پشتیبانی میکنه و کور اصلیش با زبان Rust نوشته شده.• پرفورمنس چشمگیر؛ توی خیلی از بنچمارکها، گرانیان توی هندل کردن ریکوئستهای همزمان عملکرد بهتری نسبت به
Uvicorn و Gunicorn نشون داده. بخشهای مربوط به نتورکینگ و مدیریت کانکشنها توسط Rust انجام میشن و همین باعث میشه سربار اجرای این بخشها کمتر باشه.• پشتیبانی از
HTTP/2 و WebSocket؛ از HTTP/2 و WebSocket بهصورت نیتیو پشتیبانی میکنه و برای استفاده از این قابلیتها معمولاً به کانفیگ پیچیده یا پکیجهای اضافه نیازی ندارید.• مهاجرت ساده؛ اگه پروژهتون بر پایهی
ASGI باشه، معمولاً کافیه به جای کامند Uvicorn، پروژه رو با Granian اجرا کنید؛ بدون اینکه لازم باشه لاجیک برنامهتون رو تغییر بدید.اگه پروژهتون زیر لود بالاست یا صرفا دوست دارید ابزارهای جدید اکوسیستم پایتون رو امتحان کنید، گرانیان قطعا ارزش تست کردن رو داره. البته هیچ بنچمارکی جای تست روی پروژهی واقعی خودتون رو نمیگیره؛ پس قبل از مهاجرت، حتماً عملکردش رو روی
Workload واقعی اپلیکیشنتون مقایسه کنید.📦 github.com/emmett-framework/granian
⌨• #DevEdu@Melfex
1❤🔥2👍1🔥1
جملهای معروف وجود داره که معمولا به اینشتین نسبت داده میشه: «اگه نمیتونی یه موضوع رو برای یه بچهی ۶ ساله توضیح بدی، یعنی خودت هم هنوز اون رو کامل نفهمیدی»
این دقیقا همون ایدهایه که پشت «تکنیک فاینمن» قرار داره؛ توی دنیای برنامهنویسی هم نمونهی معروفش «دیباگ با اردک پلاستیکی» هست.
خیلی وقتها ساعتها روی یه باگ گیر میکنیم و لاگها رو زیر و رو میکنیم، ولی راهحل پیدا نمیشه. ذهنمون توی یه لوپ بسته گیر افتاده و مدام همون فرضیات اشتباه قبلی رو تکرار میکنه.
جادو از لحظهای شروع میشه که سعی میکنی مشکل پروژهات رو بلندبلند برای یه نفر دیگه ( یا حتی یه شیء ) توضیح بدی. وقتی مجبور میشی کانتکست پیچیدهی کدت رو به کلمات ساده و منطقی ترجمه کنی، ناخودآگاه قدمبهقدم لاجیک رو دوباره میسازی.
هنر سادهسازی فقط مخصوص کلاس درس و تدریس نیست؛ یکی از قدرتمندترین ابزارهای دیباگینگ توی مهندسی نرمافزاره. خیلی وقتها مشکل داخل کد نیست؛ داخل مدل ذهنیه که از کد ساختیم.
👤• #FromFarshad@Melfex
این دقیقا همون ایدهایه که پشت «تکنیک فاینمن» قرار داره؛ توی دنیای برنامهنویسی هم نمونهی معروفش «دیباگ با اردک پلاستیکی» هست.
خیلی وقتها ساعتها روی یه باگ گیر میکنیم و لاگها رو زیر و رو میکنیم، ولی راهحل پیدا نمیشه. ذهنمون توی یه لوپ بسته گیر افتاده و مدام همون فرضیات اشتباه قبلی رو تکرار میکنه.
جادو از لحظهای شروع میشه که سعی میکنی مشکل پروژهات رو بلندبلند برای یه نفر دیگه ( یا حتی یه شیء ) توضیح بدی. وقتی مجبور میشی کانتکست پیچیدهی کدت رو به کلمات ساده و منطقی ترجمه کنی، ناخودآگاه قدمبهقدم لاجیک رو دوباره میسازی.
هنر سادهسازی فقط مخصوص کلاس درس و تدریس نیست؛ یکی از قدرتمندترین ابزارهای دیباگینگ توی مهندسی نرمافزاره. خیلی وقتها مشکل داخل کد نیست؛ داخل مدل ذهنیه که از کد ساختیم.
👤• #FromFarshad@Melfex
⚡2🔥1👌1
عادتها، وقتی بیشترین اهمیت را دارند که کمترین انگیزه را برای ادامه دادن داریم.
شاید سختترین روزهای زندگی، همون روزهایی باشن که هیچ انگیزهای برای ادامه نیست؛ اما دقیقا همون روزها هستند که سیستم، جای انگیزه رو میگیره.
بعضی اتفاقها، مسیر زندگی رو عوض میکنن؛ اما قرار نیست هویت ما رو تعریف کنن. انتخابهای امروز، بلندتر از اتفاقهای دیروز حرف میزنن.
📚• #FReading@Melfex | #عادت_های_اتمی
🔥2👏1
همهی ما از زخمهامون حرف میزنیم. از چیزهایی که شکستنمون، از آدمهایی که باعث شدن سختتر اعتماد کنیم، از دردهایی که قبل از ورود بعضی آدمها به زندگیمون داشتیم. و درست هم هست، هیچکس نباید دردهای خودش رو تبدیل به درد آدم دیگهای کنه.
اما یه بخش دیگهای هم وجود داره که کمتر دربارهش حرف میزنیم، وقتی کسی وارد زندگی یه آدم میشه، وقتی از گذشتهاش خبر داره، وقتی از ترسها، ضعفها و زخمهاش میدونه، وقتی خودش انتخاب میکنه نزدیک بشه، اون آدم فقط وارد یه رابطه نشده؛ وارد دنیای یه انسان شده. ورودی که انتخاب خودش بوده.
شاید هیچکس مجبور نباشه برای همیشه بمونه، شاید هیچکس رو نمیشه با اجبار نگه داشت. اما بین «حق رفتن» و «نحوهی رفتن» تفاوت بزرگی وجود داره.
گاهی آدمها فکر میکنن چون تصمیمشون برای خودشون درست بوده، پس هیچ مسئولیتی نسبت به اثری که روی دیگری گذاشتن ندارن. در حالی که میشه یه تصمیم درست واسهی خودت بگیری، اما همچنان بپذیری که اون تصمیم، برای یه نفر دیگه دردناک بوده.
همهی ما حق داریم از زخمهامون بگیم، اما ایکاش یادمون باشه داستان همیشه فقط از جایی شروع نمیشه که ما آسیب دیدیم.
خیلی وقتها قبل از اینکه از دردهای خودمون بگیم، باید یه لحظه فکر کنیم شاید ما هم توی داستان یه نفر دیگه، یه فصل سخت بودیم. نه واسهی محکوم کردن، واسه انسانتر شدن.
و شاید تموم چیزی که از ما توی زندگی آدمها باقی میمونه، نه حضورمون؛ بلکه صداییه که بعد از رفتنمون توی ذهن و قلبشون میپیچه. بنظرم سعی کنیم که خرابش نکنیم.
نمیدونم اسمش دعاست یا نتیجهی انتخابهامون؛ اما امیدوارم هر کسی، روزی با اثری که توی زندگی دیگران گذاشته روبهرو بشه.
و در آخر:
•👤 #FromFarshad@Melfex
اما یه بخش دیگهای هم وجود داره که کمتر دربارهش حرف میزنیم، وقتی کسی وارد زندگی یه آدم میشه، وقتی از گذشتهاش خبر داره، وقتی از ترسها، ضعفها و زخمهاش میدونه، وقتی خودش انتخاب میکنه نزدیک بشه، اون آدم فقط وارد یه رابطه نشده؛ وارد دنیای یه انسان شده. ورودی که انتخاب خودش بوده.
شاید هیچکس مجبور نباشه برای همیشه بمونه، شاید هیچکس رو نمیشه با اجبار نگه داشت. اما بین «حق رفتن» و «نحوهی رفتن» تفاوت بزرگی وجود داره.
گاهی آدمها فکر میکنن چون تصمیمشون برای خودشون درست بوده، پس هیچ مسئولیتی نسبت به اثری که روی دیگری گذاشتن ندارن. در حالی که میشه یه تصمیم درست واسهی خودت بگیری، اما همچنان بپذیری که اون تصمیم، برای یه نفر دیگه دردناک بوده.
همهی ما حق داریم از زخمهامون بگیم، اما ایکاش یادمون باشه داستان همیشه فقط از جایی شروع نمیشه که ما آسیب دیدیم.
خیلی وقتها قبل از اینکه از دردهای خودمون بگیم، باید یه لحظه فکر کنیم شاید ما هم توی داستان یه نفر دیگه، یه فصل سخت بودیم. نه واسهی محکوم کردن، واسه انسانتر شدن.
و شاید تموم چیزی که از ما توی زندگی آدمها باقی میمونه، نه حضورمون؛ بلکه صداییه که بعد از رفتنمون توی ذهن و قلبشون میپیچه. بنظرم سعی کنیم که خرابش نکنیم.
نمیدونم اسمش دعاست یا نتیجهی انتخابهامون؛ اما امیدوارم هر کسی، روزی با اثری که توی زندگی دیگران گذاشته روبهرو بشه.
و در آخر:
این جهان کوه است و فعل ما ندا / سوی ما آید نداها را صدا.
•👤 #FromFarshad@Melfex
👏3
اگه تا حالا واسه یه
مشکل از همینجا شروع میشه. فرض کنید یه سرویس به خاطر فشار زیاد، موقتا از دسترس خارج شده. اگه هزاران کلاینت دقیقا همون لحظه دوباره
راهحل؟! مفهومی به اسم
اما هنوز یه مشکل باقی میمونه؛ اگه همهی کلاینتها دقیقاً با همین الگو
اینجاست که مفهوم
⌨• #DevEdu@Melfex
API مکانیزم Retry نوشتید، احتمالا اولین چیزی که به ذهنتون رسیده این بوده که «اگه ریکوئست Fail شد، دوباره همون لحظه ارسالش کنم»مشکل از همینجا شروع میشه. فرض کنید یه سرویس به خاطر فشار زیاد، موقتا از دسترس خارج شده. اگه هزاران کلاینت دقیقا همون لحظه دوباره
Retry کنن، فشار بیشتری به همون سرویس وارد میکنن و عملا زمان بازیابیش طولانیتر میشه.راهحل؟! مفهومی به اسم
Exponential Backoff. به جای اینکه بعد از هر ارور فورا ریکوئست رو تکرار کنید، هر بار مدت بیشتری صبر میکنید؛ مثلا ۱ ثانیه، بعد ۲ ثانیه، بعد ۴ ثانیه، بعد ۸ ثانیه و.. اما هنوز یه مشکل باقی میمونه؛ اگه همهی کلاینتها دقیقاً با همین الگو
Retry کنن، باز هم همزمان به سرور اتک میزنن.اینجاست که مفهوم
Jitter وارد بازی میشه. به هر Retry یه مقدار تأخیر رندوم اضافه میکنه تا ریکوئستها بین کلاینتها پخش بشن و همزمان به سرور نرسن.⌨• #DevEdu@Melfex
❤2👍2
اگه برای تست پروژههاتون تا حالا مجبور شدید یه
وقتشه با
• تست روی سرویس واقعی: به جای ماک کردن دیتابیس یا
• ایزوله و قابل تکرار: هر بار اجرای تست، کانتینرهای جدید ساخته میشن و بعد از اتمام تستها هم حذف میشن. در نتیجه هیچ دیتای باقیمونده یا تنظیمات قبلی روی نتیجه تست تأثیر نمیذاره.
• سازگار با CI/CD: چون همهچیز خودکار بالا میاد، اجرای تستها روی گیتهاب
📦 github.com/testcontainers
⌨• #DevEdu@Melfex
PostgreSQL، Redis یا RabbitMQ روی سیستم نصب کنید، احتمالا با این سناریو هم آشنا هستید: «روی سیستم من کار میکنه». یکی از دلایل اصلی این اتفاق، تفاوت محیط توسعه با محیطیه که تستها داخلش اجرا میشن.وقتشه با
Testcontainers آشنا بشید. Testcontainers یه ماژول و کتابخونه اوپنسورسه که بهتون اجازه میده موقع اجرای تستها، سرویسهای واقعی مثل PostgreSQL، Redis، RabbitMQ، Kafka و دهها سرویس دیگه رو داخل داکر بالا بیارید؛ اون هم بهصورت کاملا خودکار و موقت.• تست روی سرویس واقعی: به جای ماک کردن دیتابیس یا
Redis، تستهاتون مستقیما روی همون سرویسی اجرا میشن که قراره توی پروداکشن ازش استفاده کنید.• ایزوله و قابل تکرار: هر بار اجرای تست، کانتینرهای جدید ساخته میشن و بعد از اتمام تستها هم حذف میشن. در نتیجه هیچ دیتای باقیمونده یا تنظیمات قبلی روی نتیجه تست تأثیر نمیذاره.
• سازگار با CI/CD: چون همهچیز خودکار بالا میاد، اجرای تستها روی گیتهاب
Actions یا هر سیستم CI دیگهای هم دقیقا مثل سیستم توسعهدهنده هست.📦 github.com/testcontainers
⌨• #DevEdu@Melfex
🔥3
چهار هزار هفته.pdf
24.2 MB
احتمالا اسم این کتاب رو بارها شنیدید؛ اما با توجه به چیزهایی که تا امروز دربارهش شنیده بودم، به نظرم چیزی که باعث شده اینقدر ماندگار بشه، فقط محبوبیتش نیست، بلکه نگاه متفاوتش به مفهوم «زمان» و «زندگی» هست. برخلاف خیلی از کتابهای توسعه فردی که مدام از بهرهوری بیشتر، مدیریت زمان و انجام دادن کارهای بیشتر حرف میزنن، این کتاب از یه زاویه کاملا متفاوت به موضوع نگاه میکنه.
طبق روال معمول، میتونید کوت و پاراگرافهایی که از نظر من ارزش بیشتری دارن رو با هشتگ #چهار_هزار_هفته دنبال کنید.
در آخر، اگه امکانش براتون فراهمه، نسخه اصلی و قانونی کتاب رو تهیه کنید. من هم نسخه قانونی کتاب رو خریدم.
📚• #FReading@Melfex | #چهار_هزار_هفته
طبق روال معمول، میتونید کوت و پاراگرافهایی که از نظر من ارزش بیشتری دارن رو با هشتگ #چهار_هزار_هفته دنبال کنید.
در آخر، اگه امکانش براتون فراهمه، نسخه اصلی و قانونی کتاب رو تهیه کنید. من هم نسخه قانونی کتاب رو خریدم.
📚• #FReading@Melfex | #چهار_هزار_هفته
❤🔥3🤔1
این احساس که باید از زمان محدود خود نهایت استفاده را کنیم، ریشه در این ایده دارد که زمان چیزی است که باید از آن استفاده کنیم.
بهتر است کاری انجام دهیم که ارزش انجام دادن داشته باشد و اجازه دهیم به پایان برسد، تا اینکه مدام درگیرِ جبرانِ کمبودهای زندگی و مدیریتِ بیپایانِ کارها باشیم.
فکر میکنم یکی از بزرگترین توهمهایی که این روزها باهاش زندگی میکنیم، اینه که یه روز بالاخره همهی کارهامون تموم میشن؛ فقط کافیه برنامهریزی بهتری داشته باشیم، سریعتر کار کنیم یا ابزار بهتری پیدا کنیم. اما شاید اصلا قرار نیست چنین روزی از راه برسه.
شاید مسئله، مدیریت بهتر زمان نباشه؛ بلکه پذیرفتن این واقعیته که زمان ما محدوده و دقیقا به همین خاطر، هر «آره» گفتن، یعنی به چیز دیگهای «نه» گفتن.
به نظرم آرامش، از انجام دادنِ کارهای بیشتر نمیاد؛ از انتخاب کردنِ کارهای مهمتر میاد.
📚• #FReading@Melfex | #چهار_هزار_هفته
❤2👏1
اگه با داکر کار میکنید، احتمالا با این سناریو آشنا هستین که: واسه دیدن وضعیت کانتینرها، بررسی لاگها یا اجرای یه کامند ساده، مدام بین کامندها جابهجا میشین.
از طرفی ابزارهای گرافیکی مدیریت داکر همیشه برای هر سناریویی مناسب نیستن؛ مخصوصا وقتی روی سرورهای ریموت یا محیطهای کممنبع کار میکنید و دنبال یک راهحل سریع و سبک هستید.
اینجاست که
• مدیریت در یک محیط واحد؛ میتونید وضعیت کانتینرها، ایمیجها، والیومها و سرویسهای داکر
• لاگ و Shell سریع؛ با چند حرکت ساده میتونید لاگهای لایو کانتینرها رو ببینید، وارد شل یک کانتینر بشید و کارتون رو انجام بدین.
• نمایش مصرف منابع؛ امکان مشاهدهی مصرف
📦 github.com/jesseduffield/lazydocker
⌨• #DevEdu@Melfex
از طرفی ابزارهای گرافیکی مدیریت داکر همیشه برای هر سناریویی مناسب نیستن؛ مخصوصا وقتی روی سرورهای ریموت یا محیطهای کممنبع کار میکنید و دنبال یک راهحل سریع و سبک هستید.
اینجاست که
Lazydocker میتونه تجربهی کار با داکر رو راحتتر کنه. لیزیداکر یه ابزار TUI هست که با گولنگ نوشته شده و محیط داکر و داکر Compose شما رو مستقیما داخل ترمینال به یه داشبورد تعاملی تبدیل میکنه. • مدیریت در یک محیط واحد؛ میتونید وضعیت کانتینرها، ایمیجها، والیومها و سرویسهای داکر
Compose رو بدون نیاز به اجرای چندین کامند مختلف مشاهده و مدیریت کنید.• لاگ و Shell سریع؛ با چند حرکت ساده میتونید لاگهای لایو کانتینرها رو ببینید، وارد شل یک کانتینر بشید و کارتون رو انجام بدین.
• نمایش مصرف منابع؛ امکان مشاهدهی مصرف
CPU و RAM کانتینرها بهصورت گرافیکی داخل ترمینال وجود داره. 📦 github.com/jesseduffield/lazydocker
⌨• #DevEdu@Melfex
👍2❤🔥1🔥1🥰1
مشکل ما با زمان، کمبود آن نیست؛ مشکل این است که باور داریم باید از پسِ همهی کارها بربیاییم. بهرهوریِ مدرن به ما یاد داده که "فقط یک ترفندِ دیگر" میتواند همهچیز را درست کند؛ اما حقیقت این است که هرچه سریعتر پیش میرویم، فهرستِ کارهایی که "باید انجام بدهیم" بلندتر میشود. تا زمانی که نپذیریم محدودیت، بخشی جداییناپذیر از زندگی است، این احساسِ "عقب ماندن" هیچوقت رهایمان نمیکند
شاید بزرگترین فریب دنیای امروز این باشه که ارزش ما رو با میزان بهرهوریمون گره زده. انگار هرچی کارهای بیشتری انجام بدیم، آدم موفقتر و خوشحالتری هستیم؛ اما واقعیت اینه که فهرست کارها هیچوقت تموم نمیشن.
بهنظرم نقطهی رهایی، پیدا کردن یه ترفند جدید واسه مدیریت زمان نیست؛ بلکه پذیرفتن این واقعیته که قرار نیست همهچیز رو انجام بدیم. وقتی این محدودیت رو بپذیریم، دیگه مدام خودمون رو با یه لیست بیانتها قضاوت نمیکنیم و میتونیم انرژیمون رو روی همون چندتا کاری بذاریم که واقعا واسمون اهمیت دارن.
📚• #FReading@Melfex | #چهار_هزار_هفته
❤3🔥1💘1 1
اگه از دیدن
یه فریمورک پایتونی به نام
• استایلدهی مثل وب؛
• ویژگیهای
• ترمینال یا مرورگر؛ جالبترین بخشش اینه که میتونید همون اپلیکیشن رو داخل ترمینال اجرا کنید یا با
اگه دوست دارید چیزی فراتر از
🐱 github.com/Textualize/textual
🔨 • #DevEdu@Melfex
TUIهایی مثل Lazydocker لذت بردید، ولی فکر میکردید ساختن همچین اپهایی فقط با گولنگ یا راست ممکنه، وقتشه نظرتون عوض بشه.یه فریمورک پایتونی به نام
Textual هست که بهتون اجازه میده اپلیکیشنهای ترمینالی کاملا تعاملی، با انیمیشن روان، پشتیبانی از موس و حتی ۱۶.۷ میلیون رنگ بسازید؛ اون هم با پایتون.• استایلدهی مثل وب؛
Textual یه سیستم CSS داره که میتونید باهاش Layout، رنگ، Border و حتی حالتهای مختلف Widgetها رو کنترل کنید؛ بدون اینکه استایل رو با لاجیک پایتون قاطی کنید.• ویژگیهای
Reactive؛ کافیه یه متغیر رو reactive تعریف کنید تا با تغییر مقدارش، Textual بهصورت خودکار UI رو رفرش کنه؛ الگویی که برای توسعهدهندههای فرانتاند خیلی آشناست.• ترمینال یا مرورگر؛ جالبترین بخشش اینه که میتونید همون اپلیکیشن رو داخل ترمینال اجرا کنید یا با
textual serve توی مرورگر در دسترس قرار بدید.اگه دوست دارید چیزی فراتر از
print و لاگهای ساده توی ترمینال بسازید، Textual میتونه یکی از جذابترین گزینههای اکوسیستم پایتون برای ساخت TUI باشه.Please open Telegram to view this post
VIEW IN TELEGRAM
یکی از رایجترین اشتباهاتی که توی کدهای
❗️ قبل:
این کد از نظر سینتکس هیچ ایرادی نداره؛ اما پراسس/عملیاتها عملا سریالی اجرا میشن. چون هر
💡 اولین راهحلی که معمولا به ذهن میرسه:
سریعتره، ولی حالا مشکل برعکس شده؛ همهی ریکوئستها بدون هیچ محدودیتی شلیک میشن. یادتونه توی پست آنتیاسپم دربارهی
💡 راهحل بعدی، محدود کردن تعداد پراسس همزمانه:
اما اینجا یه تفاوت مهم وجود داره:
توی این حالت،
اینجا بود که توی
اینجا یوزرها
این روش هم مثل
یه بخش دیگهی این کد هم به نظرم مهمتر از خود
اینجا دیگه لازم نیست حدس بزنیم چقدر باید صبر کنیم؛ خود
و شاید مهمترین چیزی که از این مثال میشه برداشت کرد اینه:
👨💻• #CodeSmell@Melfexzq
async میبینم رو امروز میخوام باهم مرور کنیم؛ لوپ زدن روی یه لیست و await کردن هر آیتم بهصورت جداگانه.❗️ قبل:
async def notify_users(user_ids: list[int]):
for user_id in user_ids:
await bot.send_message(
user_id,
"بروزرسانی جدید منتشر شد!"
)
این کد از نظر سینتکس هیچ ایرادی نداره؛ اما پراسس/عملیاتها عملا سریالی اجرا میشن. چون هر
coroutine رو قبل از رفتن سراغ کاربر بعدی await میکنیم، iteration بعدی تا تموم شدن عملیات قبلی شروع نمیشه. واسهی ۱۰۰۰ یوزر یعنی ۱۰۰۰ ریکوئست شبکه که یکییکی منتظر هم میمونن.💡 اولین راهحلی که معمولا به ذهن میرسه:
async def notify_users(user_ids: list[int]):
await asyncio.gather(*[
bot.send_message(
uid,
"بروزرسانی جدید منتشر شد!"
)
for uid in user_ids
])
سریعتره، ولی حالا مشکل برعکس شده؛ همهی ریکوئستها بدون هیچ محدودیتی شلیک میشن. یادتونه توی پست آنتیاسپم دربارهی
FloodWait تلگرام صحبت کردیم؟ اینجا خود بات میتونه تبدیل بشه به همون چیزی که ازش فرار میکردیم. 😂💡 راهحل بعدی، محدود کردن تعداد پراسس همزمانه:
sem = asyncio.Semaphore(20)
async def send_one(uid: int):
async with sem:
await bot.send_message(uid, "بروزرسانی جدید منتشر شد!")
اما اینجا یه تفاوت مهم وجود داره:
Concurrency Limit ≠ Rate Limit
توی این حالت،
Semaphore(20) فقط میگه حداکثر ۲۰ عملیات همزمان داشته باش؛ نمیگه در هر ثانیه حداکثر چند ریکوئست ارسال کنی. مثلا اگه ریکوئستها خیلی سریع تموم بشن، به محض آزاد شدن هر slot، عملیات بعدی میتونه شروع بشه و توی یه بازهی کوتاه تعداد زیادی ریکوئست ارسال بشه. اینجا بود که توی
broadcaster.py پروژهی Telegram-MSG-Bridge خودم، بهجای Semaphore از یه مدل سادهتر برای Broadcast استفاده کردم:for start in range(0, len(recipients), self._per_second):
batch = recipients[
start : start + self._per_second
]
outcomes = await asyncio.gather(
*(
self._send_one(
uid,
from_chat_id,
message_id
)
for uid in batch
)
)
sent += sum(outcomes)
if start + self._per_second < len(recipients):
await asyncio.sleep(1.0)
اینجا یوزرها
batch به batch پردازش میشن؛ مثلا ۲۰ تا همزمان ارسال میشن، منتظر میمونیم کل batch تموم بشه، یک ثانیه صبر میکنیم و بعد میریم سراغ batch بعدی.این روش هم مثل
Rate Limiterهای واقعی دقیق نیست؛ چون زمان هر batch به کندترین ریکوئست همون batch بستگی داره. اما واسهی یه broadcaster ساده، در عوض پیادهسازی خیلی راحتتری داره و رفتار نرخ ارسال رو قابل پیشبینیتر میکنه.یه بخش دیگهی این کد هم به نظرم مهمتر از خود
batching هست:except TelegramRetryAfter as error:
await asyncio.sleep(error.retry_after)
try:
await self._bot.copy_message(...)
return True
except TelegramAPIError:
return False
اینجا دیگه لازم نیست حدس بزنیم چقدر باید صبر کنیم؛ خود
Telegram API مقدار retry_after رو برمیگردونه و ما دقیقا به همون اندازه صبر میکنیم. البته این کد عمدا فقط یه بار retry میکنه. اگه ریکوئست دوم هم دوباره با ارور API مواجه بشه، اون کاربر failed حساب میشه؛ چون واسهی یه broadcaster ساده، جلوگیری از retry-loop بینهایت مهمتر از تلاش نامحدود واسهی یه پیام خاصه.و شاید مهمترین چیزی که از این مثال میشه برداشت کرد اینه:
ایسینک بودن بهتنهایی یعنی کانکارنسی؛ نه لزوماً Rate Limiting.👨💻• #CodeSmell@Melfexzq
یکی از خطرناکترین حسها توی مسیر یادگیری برنامهنویسی، حسیه که شاید کمتر دربارهش حرف زده میشه: توهمِ فهمیدن.
یه مفهوم جدید یاد میگیرید؛ یه مقاله میخونید، یه ویدیو میبینید یا کد یه نفر دیگه رو بررسی میکنید. همهچیز منطقی به نظر میرسه. هر خط رو متوجه میشید و در آخر با خودتون میگید: «آها، فهمیدم.»
اما مشکل اینجاست که مغز ما بین «آشنا بودن» و «بلد بودن» تفاوت زیادی قائل نمیشه. وقتی چیزی رو دوباره میبینه، سریع حس آشنایی ایجاد میکنه و همین حس گاهی با یادگیری واقعی اشتباه گرفته میشه.
در حالی که تشخیص دادن یه مفهوم، با توانایی ساختن اون مفهوم دو مهارت کاملا متفاوتن. ممکنه هنگام خوندن یه پیادهسازی، همهچیز واضح باشه؛ اما وقتی یه فایل خالی باز میکنید و میخواید همون ایده رو از صفر پیاده کنید، تازه مشخص میشه کدوم بخشها واقعا توی ذهنتون تثبیت شده و کدوم بخشها فقط آشنا به نظر میرسیدن.
به نظرم یکی از بهترین روشها برای سنجیدن یادگیری، همین لحظهست: منبع رو ببندید و تلاش کنید چیزی که یاد گرفتید رو بدون کمک دوباره بسازید. نه برای اینکه خودتون رو امتحان کنید، بلکه برای اینکه بفهمید دقیقا کجای مسیر هستید.
شاید برای همینه که من همیشه ترجیح میدم از کدهای واقعی پروژهها مثال بزنم، نه مثالهای کوچیک و مصنوعی. چون یه کد واقعی، قبل از اینکه به شما نمایش داده بشه، یه مرحلهی مهم رو پشت سر گذاشته؛ مرحلهای که خیلی از آموزشها حذفش میکنن: مرحلهی تولید کردن. جایی که دیگر فقط شناختن یک راهحل کافی نیست؛ باید تصمیم بگیرید، اشتباه کنید، دیباگ کنید و در نهایت چیزی بسازید.
پس دفعهی بعد که حس کردید یک مفهوم رو کامل یاد گرفتید، اول از همه بسنجید این حس رو.
👤 • #FromFarshad@Melfex
یه مفهوم جدید یاد میگیرید؛ یه مقاله میخونید، یه ویدیو میبینید یا کد یه نفر دیگه رو بررسی میکنید. همهچیز منطقی به نظر میرسه. هر خط رو متوجه میشید و در آخر با خودتون میگید: «آها، فهمیدم.»
اما مشکل اینجاست که مغز ما بین «آشنا بودن» و «بلد بودن» تفاوت زیادی قائل نمیشه. وقتی چیزی رو دوباره میبینه، سریع حس آشنایی ایجاد میکنه و همین حس گاهی با یادگیری واقعی اشتباه گرفته میشه.
در حالی که تشخیص دادن یه مفهوم، با توانایی ساختن اون مفهوم دو مهارت کاملا متفاوتن. ممکنه هنگام خوندن یه پیادهسازی، همهچیز واضح باشه؛ اما وقتی یه فایل خالی باز میکنید و میخواید همون ایده رو از صفر پیاده کنید، تازه مشخص میشه کدوم بخشها واقعا توی ذهنتون تثبیت شده و کدوم بخشها فقط آشنا به نظر میرسیدن.
به نظرم یکی از بهترین روشها برای سنجیدن یادگیری، همین لحظهست: منبع رو ببندید و تلاش کنید چیزی که یاد گرفتید رو بدون کمک دوباره بسازید. نه برای اینکه خودتون رو امتحان کنید، بلکه برای اینکه بفهمید دقیقا کجای مسیر هستید.
شاید برای همینه که من همیشه ترجیح میدم از کدهای واقعی پروژهها مثال بزنم، نه مثالهای کوچیک و مصنوعی. چون یه کد واقعی، قبل از اینکه به شما نمایش داده بشه، یه مرحلهی مهم رو پشت سر گذاشته؛ مرحلهای که خیلی از آموزشها حذفش میکنن: مرحلهی تولید کردن. جایی که دیگر فقط شناختن یک راهحل کافی نیست؛ باید تصمیم بگیرید، اشتباه کنید، دیباگ کنید و در نهایت چیزی بسازید.
پس دفعهی بعد که حس کردید یک مفهوم رو کامل یاد گرفتید، اول از همه بسنجید این حس رو.
Please open Telegram to view this post
VIEW IN TELEGRAM
1 3 1 1
AliiReza 13
مگه هدف async این نیست که وقتی کروتین اجرا میشه تا وقتی جوابش نرسیده برنامه منتظرش نمیمونه و میره سراغ پروسه بعدی؟ پس چرا اینجا میگی ارسال پیام بعدی باید برای ارسال پیام قبلی صبر کنه؟
نکته همینه:
این کد رو ببینید:
وقتی به
در واقع چیزی شبیه این اتفاق میافته:
اما اگر کارها رو از قبل بهعنوان تسک زمانبندی کنیم:
اینجا هر دو تا تسک واسهی اجرا به ایونت لوپ سپرده شدن. بنابراین وقتی
پس یه سوءتفاهم رایج اینه که فکر کنیم
و:
اولی عملیات دوم رو تا رسیدن نوبتش اصلا شروع نکرده؛ دومی هر دو عملیات رو از قبل
اگه بخوام کل ماجرا رو توی یه جمله خلاصه و سرتون رو درد نیارم:
💡• #AskFarshad@Melfex
async بهتنهایی باعث concurrent شدن همهی عملیات/پراسس نمیشه. توی asyncio باید چند کار واقعا برای اجرا به Event loop سپرده شده باشن تا وقتی یکی منتظر I/O میمونه، ایونت لوپ بتونه سراغ کار دیگهای بره.این کد رو ببینید:
for user_id in user_ids:
await bot.send_message(user_id, "...")
وقتی به
await یوزر اول میرسیم، هنوز اصلا به iteration بعدی نرسیدیم؛ یعنی عملیات مربوط به کاربر دوم هنوز شروع یا schedule نشده. بنابراین تا عملیات اول کامل نشه، لوپ سراغ یوزر بعدی نمیره.در واقع چیزی شبیه این اتفاق میافته:
await task1()
await task2()
اما اگر کارها رو از قبل بهعنوان تسک زمانبندی کنیم:
t1 = asyncio.create_task(task1())
t2 = asyncio.create_task(task2())
await t1
await t2
اینجا هر دو تا تسک واسهی اجرا به ایونت لوپ سپرده شدن. بنابراین وقتی
task1 منتظر I/O میمونه، ایونت لوپ میتونه توی همین فاصله task2 رو هم پیش ببره. واسهی همین سناریو asyncio.gather هم خیلی کاربردیه؛ وقتی coroutineها رو بهش میدیم، اونها رو بهصورت تسک زمانبندی میکنه و منتظر میمونه تا همه کامل بشن.پس یه سوءتفاهم رایج اینه که فکر کنیم
await یعنی: "صبر کن، بعد برو سراغ کار بعدی". در حالی که دقیقترش اینه که await یعنی: "این coroutine توی این نقطه منتظر بمونه؛ اگ ایونت لوپ کار دیگهای واسهی اجرا داشته باشه، میتونه توی همین فاصله اون رو پیش ببره" و این دقیقا دلیل تفاوت بین این دو تا حالته:await task1()
await task2()
و:
t1 = asyncio.create_task(task1())
t2 = asyncio.create_task(task2())
await t1
await t2
اولی عملیات دوم رو تا رسیدن نوبتش اصلا شروع نکرده؛ دومی هر دو عملیات رو از قبل
schedule کرده.اگه بخوام کل ماجرا رو توی یه جمله خلاصه و سرتون رو درد نیارم:
ایسینک به شما امکانconcurrencyمیده؛ اما این شمایید که باید مشخص کنید چه کارهایی همزمان در اختیارEvent Loopقرار بگیرن.
💡• #AskFarshad@Melfex
2 3 1