گزاره defer در زبان برنامه‌نویسی Go – راهنمای کاربردی

۳۲۹ بازدید
آخرین به‌روزرسانی: ۱۲ مهر ۱۴۰۲
زمان مطالعه: ۴ دقیقه
دانلود PDF مقاله
گزاره defer در زبان برنامه‌نویسی Go – راهنمای کاربردیگزاره defer در زبان برنامه‌نویسی Go – راهنمای کاربردی

گزاره defer در زبان برنامه‌نویسی Go یک روش آسان برای اجرای یک قطعه کد پیش از بازگشت تابع است. طبق مستندات Go تابع‌های defer شده به جای اجرای بی‌درنگ پیش از بازگشت تابع پیرامونی، به طور عکس خودشان به تأخیر می‌افتند. در ادامه مثالی از پیاده‌سازی LIFO را می‌بینید:

997696

در ادامه به توضیح سازوکار داخلی این گزاره می‌پردازیم و سپس یک حالت پیچیده‌تر را مطرح می‌کنیم.

پیاده‌سازی داخلی

محیط زمان اجرای Go اقدام به پیاده‌سازی LIFO با استفاده از یک لیست پیوندی می‌کند. در واقع یک struct تأخیر دار لینکی به struct بعدی که باید اجرا شود دارد:

زمانی که یک متد defer جدید ایجاد می‌شود، به Goroutine جاری وصل می‌شود و قبلی به متد فعلی لینک می‌شود چون تابع بعدی باید اجرا شود:

فراخوانی‌های متوالی اینک بدون پشته هستند و تابع‌های defer شده از بالا به صورت زیر هستند:

چنان که می‌بینیم ما تابع‌های defer شده را در حلقه قرار نمی‌دهیم، بلکه یک به یک از پشته خارج می‌شوند. این رفتار از سوی کد ASM تولیدشده تأیید می‌شود:

متد deferproc دو بار فراخوانی می‌شود و به صورت درونی متد newdefer که قبلاً برای ثبت تابعمان به صوت متدهای defer شده دیدیم، فراخوانی می‌کند. در نهایت در پایان تابع، متد defer شده به لطف تابع deferreturn یک به یک فراخوانی می‌شود.

کتابخانه Go به ما نشان داد که struct به نام defer_‎ به خصوصیت panic *_panic_‎ نیز لینک شده است. در ادامه به بررسی فایده آن در طی یک مثال دیگر می‌پردازیم.

Defer و مقدار بازگشتی

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

اگر تابع defer شده یک function literal باشد و تابع پیرامونی دارای پارامترهای نتیجه با نام باشد که در دامنه literal قرار دارند، تابع defer شده می‌تواند به پارامترهای نتیجه پیش از بازگشت دسترسی داشته و آن‌ها را تغییر دهد.

به مثال زیر توجه کنید:

زمانی که این رفتار درک شود می‌توانیم آن را با تابع Recover ترکیب کنیم. در واقع Recover یک تابع درونی است که کنترل یک goroutine دارای panic را به دست می‌گیرد. Recover تنها درون تابع‌های defer شده مفید است.

چنان که دیدیم struct به نام defer_‎ به خصوصیت panic_‎ لینک شده است و این کار در طی یک فراخوانی panic روی می‌دهد:

در واقع متد gopanic در حالت panic پیش از فراخوانی تابع‌های defer شده فراخوانی می‌شود:

در ادامه یک مثال از تابع recover را می‌بینید که از مزیت پارامترهای نتیجه با نام استفاده می‌کند:

الحاق این دو به ما کمک می‌کند که به طرز مناسبی با تابع Recover کار کنیم و می‌توانیم خطاهایمان را به فراخوانی کننده بازگشت دهیم. برای نتیجه‌گیری از این مقاله در مورد تابع‌های defer شده نگاهی به بهبودهایی که برای ما فراهم می‌سازند می‌اندازیم.

بهبود عملکرد

آخرین نسخه‌ای که کاربرد defer را بهبود بخشیده است، نسخه 1.8 Go است. ما با اجرای بنچمارک در کتابخانه Go (بین نسخه‌های 1.78 و 1.8) می‌توانیم این بهبود را مشاهده کنیم:

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

این کد هم اینک به لطف بهینه‌سازی دوم 10 درصد سریع‌تر شده است.

اگر این مطلب برای شما مفید بوده است، آموزش‌ها زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
blanchon.vincent
دانلود PDF مقاله
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *