ویرگول
ورودثبت نام
عرفان کاظمی مقدم
عرفان کاظمی مقدمبرنامه نویس Backend ای که عاشق خوراکیه !!!
عرفان کاظمی مقدم
عرفان کاظمی مقدم
خواندن ۳ دقیقه·۲ روز پیش

استفاده از pointer ها در Golang ، عامل کندی !؟


در دنیای برنامه‌نویسی، همیشه تصورات اشتباهی درباره‌ی استفاده از اشاره‌گرها وجود داشته است. یکی از باورهای رایج این است که استفاده از اشاره‌گرها در Go می‌تواند عملکرد برنامه را بهبود بخشد، زیرا از کپی مکرر داده‌ها جلوگیری می‌کند. اما آیا این باور همیشه درست است؟ در این مقاله، به بررسی این موضوع و دلایل واقعی استفاده یا عدم استفاده از اشاره‌گرها در Go می‌پردازیم.

افسانه: استفاده از اشاره‌گرها برای بهبود عملکرد

بسیاری بر این باورند که استفاده از اشاره‌گرها باعث افزایش سرعت برنامه می‌شود، زیرا از کپی داده‌ها جلوگیری می‌کند. اما در واقعیت، استفاده از اشاره‌گرها در Go اغلب کندتر از استفاده از مقادیر است. دلیل اصلی این مسئله به وجود Garbage Collector (GC) در Go برمی‌گردد.

هنگامی که یک اشاره‌گر را به یک تابع ارسال می‌کنید، Go باید آنالیز فرار (Escape Analysis) انجام دهد تا مشخص کند که متغیر باید روی پشته (Stack) ذخیره شود یا در هیپ (Heap). این فرآیند خود مقداری سربار به برنامه اضافه می‌کند و اگر متغیر در هیپ ذخیره شود، عملکرد Garbage Collector نیز بر زمان اجرای برنامه تأثیر خواهد گذاشت.

ابزار بررسی Escape Analysis

برای بررسی اینکه یک متغیر به هیپ منتقل می‌شود یا خیر، می‌توانید از دستور زیر استفاده کنید:

go build -gcflags="-m"

این دستور اطلاعاتی مانند زیر به شما می‌دهد:

code./main.go:44:20: greet ... argument does not escape ./main.go:44:21: greeting escapes to heap ./main.go:44:21: name escapes to heap
  • اگر متغیر به هیپ منتقل نشود، روی پشته باقی می‌ماند.

  • پشته نیازی به مدیریت توسط Garbage Collector ندارد و عملیات‌های ساده‌ی push و pop روی آن کافی هستند.

چه زمانی استفاده از اشاره‌گرها منطقی است؟

1. کپی ساختارهای بزرگ

اگر ساختار داده‌ای بزرگی دارید که کپی کردن آن هزینه‌بر است، استفاده از اشاره‌گرها ممکن است منطقی‌تر باشد. برای مثال:

type LargeStruct struct { data [1000]int }

در چنین شرایطی، سربار Garbage Collector ممکن است کمتر از سربار کپی داده‌های بزرگ باشد. اما بهتر است با استفاده از ابزارهای Benchmark در Go، عملکرد برنامه را در شرایط مختلف بررسی کنید.

2. ایجاد قابلیت تغییر (Mutability)

به‌طور پیش‌فرض، Go از انتقال به‌صورت مقداری استفاده می‌کند. بنابراین، تغییرات در متغیر اصلی اعمال نمی‌شوند و فقط روی یک کپی انجام می‌گیرند. اگر نیاز دارید متغیر اصلی را تغییر دهید، باید از اشاره‌گرها استفاده کنید:

type person struct { name string } func rename(p *person) { p.name = "test" }

3. یکسان‌سازی API

برای حفظ یکپارچگی در API، اگر یک متد نیاز به اشاره‌گر دارد، بهتر است همه متدهای مرتبط با همان ساختار نیز از اشاره‌گر استفاده کنند. برای مثال:

func (p *person) rename(s string) { p.name = s } func (p *person) printName() { fmt.Println(p.name) }

این کار باعث می‌شود که توسعه‌دهندگان نیازی به یادآوری موارد خاص برای استفاده یا عدم استفاده از اشاره‌گر نداشته باشند.

4. نمایش غیاب مقدار واقعی

وقتی از مقادیر استفاده می‌کنید، همیشه مقدار صفر پیش‌فرض وجود دارد. اما اگر بخواهید غیاب یک مقدار را نشان دهید، می‌توانید از اشاره‌گرها برای مقدار nil استفاده کنید:

type exam struct { score *int }

چرا استفاده از مقادیر (Values) را ترجیح می‌دهم؟

1. جلوگیری از خطای Nil Pointer

استفاده از مقادیر به‌صورت پیش‌فرض از بروز خطای اشاره‌گرهای nil جلوگیری می‌کند. این مسئله باعث کاهش نیاز به نگارش کدهای بررسی‌کننده‌ی خطا می‌شود.

2. سادگی و امنیت بیشتر

مقادیر از تغییرات ناخواسته (Mutability) جلوگیری می‌کنند و باعث می‌شوند که کد قابل پیش‌بینی‌تر و اشکال‌زدایی آن ساده‌تر باشد.

3. الگوهای آشنا

در بسیاری از موارد، می‌توانید از روش بازگشت مقدار تغییر یافته استفاده کنید:

func rename(p person) person { p.name = "test" return p }

جمع‌بندی

استفاده از اشاره‌گرها در Go می‌تواند در برخی موارد مفید باشد، اما اغلب به اشتباه و با تصورات نادرست به کار می‌رود. بهتر است به‌جای پیش‌فرض قرار دادن استفاده از اشاره‌گرها، همیشه نیاز واقعی و تأثیر عملکردی آن را بررسی کنید. Go با ارائه ابزارهایی مانند Escape Analysis و Benchmarking به شما کمک می‌کند تا تصمیمات بهتری بگیرید و کدی ساده‌تر، امن‌تر و کارآمدتر بنویسید.

gogolang
۰
۰
عرفان کاظمی مقدم
عرفان کاظمی مقدم
برنامه نویس Backend ای که عاشق خوراکیه !!!
شاید از این پست‌ها خوشتان بیاید