چرا خوبه که Golang رو یاد بگیریم؟

http://kirael-art.deviantart.com/art/Go-lang-Mascot-458285682
http://kirael-art.deviantart.com/art/Go-lang-Mascot-458285682
این نوشته ترجمه پست Keval Patel در این آدرس هست:
https://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65
همچنین کامنت یکی از کاربران رو در آخر همین مقاله قرار دادم که به نظرم مفید واقع می‌شود.

در چند سال گذشته, زبان برنامه نویسی جدیدی ظهور کرده است: Go یا GoLang. هیچ چیز مثل یک زبون برنامه نویسی جدید یه دولوپر رو دیوونه نمیکنه, درسته؟ پس, من شروع کردم به یادگیری Go از ۴ یا ۵ ماه پیش و الان اینجام تا به شما بگم چرا خوبه که این زبان جدید رو یاد بگیریم.

من در این مقاله نمی‌خواهم به شما یاد بدم چطور یه "!!Hello, World" بنویسید. توی فضای اینترنت پر هست از این دست آموزش‌ها. من اینجام تا توضیح بدم چرا به زبون جدید Go نیاز داریم؟. بخاطر اینکه اگر هیچ مشکلی وجود نداشته باشه به راه حل‌ای هم نیاز نداریم, درسته؟


محدودیت های سخت افزاری:

قانون مور در حال شکستن است.
پ.ن: این قانون به صورت خلاصه میگه که هر ۲ سال تعداد ترانزیستور‌های روی یک تراشه دو برار می‌شود به این معنا که ابعاد آنها در هر ۲ سال در حال نصف شدن است.

اولین پردازنده Pentium 4 با سرعت 3.0GHz در سال ۲۰۰۴ توسط اینتل معرفی شد. امروز, Macbook Pro 2016 من سرعت پردازشی حدود 2.9GHz دارد. پس, در یک دهه اخیر, قدرت پردازش زیادی بدست نیامده است. شما میتونید مقایسه افزایش قدرت پردازش همراه با زمان آن را در نمودار زیر ببینید.

در نمودار بالا می‌بینید که عملکرد single-thread و فرکانس پردازنده در یک دهه ثابت مانده. اگر شما فکر می‌کنید که اضافه کردن ترانزیستورهای بیشتر راه حل هست, پس شما اشتباه میکردید.

پ.ن: ببینید طبق قانون مور که بالاتر گفتم, ابعاد ترانزیستورها هر ۲ سال نصف می‌شود, و زمانی که ابعاد ترانزیستور درحال کوچک شدن هست بعد از مدتی این موضوع محدودیت‌های فیزیکی برای سازنده پردازنده‌ها ایجاد میکند.

ویکیپدیا: این محدودیت فیزیکی دانشمندان را به این سمت سوق داده که شاخه‌های جدیدی از روش‌های محاسباتی را آزمایش کنند، تا در هنگام لزوم بتوانند جایگزین مناسبی برای رایانه‌های امروزی داشته باشند؛روش‌هایی همچون محاسبه کوانتومی، محاسبه زیستی و… . آنچه مسلم است، این است که در چنین رایانه‌هایی خبری از تراشه و CPU هایی به شکل‌های امروزی نخواهد بود.

پس راه حل‌هایی برای مشکل بالا ارائه شد:

  • تولید کنندگان شروع به افزودن هسته های بیشتر به پردازنده کردند.
    امروزه ما CPU های چهار هسته‌ای و هشت هسته‌ای در دسترس داریم.
  • ما همچنین hyper-threading را معرفی کردیم.
  • برای افزایش عملکرد ، حافظه کش بیشتری به پردازنده اضافه شده است.

اما راه حل‌های بالا محدودیت‌های خودشون رو هم دارند.
۱ - ما نمی‌توانیم حافظه کش بیشتری را به پردازنده اضافه کنیم تا عملکرد افزایش یابد چون برای حافظه کش هم محدودیت‌های فیزیکی وجود دارد به این معنا که هرچه حافظه کش بزرگتر باشد ، سرعت آن کندتر می شود.

۲ - افزودن هسته بیشتر به پردازنده, هزینه بیشتری هم دارد. همچنین ، نمی‌توان تعداد آن را به طور نامحدود افزایش داد. این پردازنده های چند هسته ای می توانند چندین Thread را به طور همزمان اجرا کنند و این موضوع برای Concurrency به ما کمک میکند که بعداً در مورد آن بحث می کنیم.

بنابراین ، اگر نمی توانیم به پیشرفت های سخت افزاری متکی باشیم ، تنها راهی که می توان از آن استفاده کرد نوشتن نرم افزار کارآمدتری برای افزایش عملکرد است. اما متأسفانه ، زبان‌های برنامه نویسی مدرن خیلی کارآمد نیستند.

گو, goroutine دارد:

همانطور که در بالا بحث کردیم, تولیدکنندگان سخت افزار برای افزایش کارایی, هسته های بیشتری به پردازنده ها اضافه می کنند. همه دیتاسنترها بر روی آن پردازنده ها کار می کنند و ما باید در سال های آینده انتظار افزایش تعداد هسته‌ها را داشته باشیم. علاوه بر این ، برنامه های امروزی از چندین micro-service برای ارتباط با پایگاه داده ، queue ها و حافظه کش استفاده می کنند. بنابراین ، نرم افزاری که توسعه می دهیم و زبانهای برنامه نویسی که استفاده می‌کنیم باید به راحتی از Concurrency پشتیبانی کنند و با افزایش تعداد هسته ها مقیاس پذیر (scalable) باشند.

اما ، اکثر زبان های برنامه نویسی مدرن (مانند جاوا ، پایتون و غیره) از دهه (’90s)
زمان برنامه های single-thread میایند. اکثر این زبان های برنامه نویسی از multi-threading می کنند. اما مشکل واقعی با اجرای برنامه های Concurrent همراه است مثل threading-locking , race conditions و deadlocks. این موارد ایجاد برنامه multi-thread را در آن زبانها را دشوار می کند.

برای مثال ، ایجاد thread در جاوا از نظر حافظه کارآمد نیست. از آنجا که هر thread تقریباً 1MB از حجم حافظه را مصرف می کند و در نهایت اگر هزاران thread را ایجاد کنید ، فشار زیادی بر روی حافظه وارد می کنند و به دلیل کمبود حافظه برنامه دچار مشکل می شود. همچنین ، اگر می خواهید بین دو یا چند thread ارتباط برقرار کنید ، ایجاد این ارتباط بسیار مشکل خواهد بود.

از سوی دیگر ، Go در سال 2009 هنگامی که پردازنده های چند هسته ای در دسترس بودند ، منتشر شد. به همین دلیل Go با در نظر گرفتن concurrency ساخته شده است. Go به جای thread دارای گوروتین (goroutine) است. آنها تقریباً 2 کیلوبایت حافظه از heap را مصرف می کنند. بنابراین ، می توانید میلیون ها گوروتین را در هر زمان استفاده کنید.

http://golangtutorials.blogspot.in/2011/06/goroutines.html :روتین چطور کار میکند؟ منبع
http://golangtutorials.blogspot.in/2011/06/goroutines.html :روتین چطور کار میکند؟ منبع


مزایای دیگر عبارتند از:

  • گوروتین ها دارای stack های قابل رشد هستند. این بدان معناست که آنها فقط در صورت نیاز از حافظه بیشتری استفاده خواهند کرد.
  • زمان راه‌اندازی (startup) گوروتین سریعتر از thread ها است.
  • گوروتین‌ها دارای ساختار built-in برای ایجاد ارتباط بین گوروتین‌های دیگر هست که با استفاده از channel ها امکان پذیر است.
  • گوروتین به شما این امکان را می دهد که هنگام به اشتراک گذاری ساختار داده ها ، مجبور نباشید از lock mutex استفاده کنید.
  • همچنین گوروتین‌های گو با thread های سیستم عامل ارتباط 1:1 ندارند. این یعنی یک گوروتین میتونه روی چندین thread اجرا بشه.
شما میتونید سخنرانی Rob Pike رو برای عمیق‌تر فهمیدن این موضوع نگاه کنید:
https://blog.golang.org/concurrency-is-not-parallelism

با تمام نکات بالا که Go را یک زبان بسیار قوی برای پشتیبانی از concurrency مثل java و C++/C میکنه در همین حال به زیبایی Erlang از آن استفاده می‌کند.

گو در هر دو زمینه راحتی و بهینگی Concurrency به خوبی عمل کرده است.
گو در هر دو زمینه راحتی و بهینگی Concurrency به خوبی عمل کرده است.



گو مستقیماً بر روی سخت افزار اجرا می شود.

یکی از مهمترین مزایای استفاده از C ، C ++ نسبت به سایر زبانهای سطح بالاتر مانند جاوا/پایتون ، عملکرد آنهاست. زیرا C/C ++ کامپایل می شوند و تفسیر نمی شوند.

پردازنده ها باینری را می فهمند. به طور کلی ، وقتی برنامه ای را با کامپایلر پروژه خود با استفاده از جاوا یا سایر زبان های مبتنی بر JVM می سازید ، کد خوانا برای انسان را به byte-code کامپایل می کند که توسط JVM یا سایر ماشین های مجازی که در بالای سیستم عامل اصلی اجرا می شوند. در حین اجرا ، VM آن byte-code هارا تفسیر کرده و آنها را به Binary تبدیل می کند که پردازنده ها می توانند آن را پردازش کنند.

مراحل اجرای برنامه تحت VM
مراحل اجرای برنامه تحت VM

در طرف دیگر ، C/C ++ روی ماشین های مجازی اجرا نمی شود و این یک مرحله از چرخه اجرا را حذف کرده و عملکرد را افزایش می دهد. این کد بطور مستقیم سورس کد را برای Binary کامپایل می کند.

مراحل کامپایل برنامه بدون VM
مراحل کامپایل برنامه بدون VM

اما مدیریت حافظه در آن زبان ها دردسر بزرگی است. در حالی که اکثر زبان های برنامه نویسی با استفاده از الگوریتم Garbage Collector یا Reference Counting مقداردهی و حذف شی را مدیریت می کنند.

گو در هر دو زمینه به خوبی عمل کرده است. هم مانند زبان های سطح پایین مثل C++/C کامپایل می‌شود. که کارایی گو را به زبان‌های سطح پایین‌تر نزدیک می‌کنم. و همچنین از Garbage collection برای مدیریت حافظه استفاده می‌کند.


نگهداری (maintain) کد نوشته شده با Go آسان است.

بزارید یک چیزی به شما بگویم. Go مانند دیگر زبانها syntax برنامه نویسی دیوانه واری ندارد و دارای syntax بسیار مرتب و تمیز است.

پ.ن: این مورد مزیت و معایب خودش رو داره که در ادامه توضیح می‌دهم.

طراحان Go در گوگل هنگام ساخت این زبان به این نکته توجه داشتند. از آنجایی که google کد بیس بسیار بزرگی دارد و هزاران توسعه دهنده بر روی همان کد بیس کار می کردند ، درک کد برای توسعه دهندگان دیگر باید ساده باشد و یک بخش کد باید کمترین side effect (تداخل شاید بشه معنی کرد!) را روی بخش‌های دیگر داشته باشد. این باعث می شود کد به راحتی قابل نگهداری و اصلاح شود.

گو عمداً بسیاری از قابلیت های زبان های OOP مدرن را کنار می گذارد.

  • گو از class ها استفاده نمی‌کند. همه چیز به چندین package تقسیم می‌شود. گو struct داره بجای کلاس‌ها.
  • از ارث‌بری پشتیبانی نمی‌کند. این باعث می شود کد به راحتی قابل تغییر باشد. در زبانهای دیگر مانند جاوا/پایتون ، اگر کلاس ABC از کلاس XYZ ارث‌بردی کند و شما تغییراتی در کلاس XYZ ایجاد کنید ، ممکن است در کلاسهای دیگری که XYZ را به ارث برده اند side effect ایجاد کند. گو با حذف وراثت ، درک کد را نیز آسان می کند (زیرا هنگام نگاه کردن به یک کد ، هیچ super classای وجود ندارد که بتوان به آن نگاه کرد).
  • بدونِ constructors.
  • بدونِ annotations.
  • بدونِ generics.
  • بدونِ exceptions.
پ.ن: هر کدام از این بدونِ‌ها :) دلایل خودشون رو دارند که در این مقاله نمی‌گنجه.

نکات بالا گو را بسیار متفاوت از زبان‌های برنامه نویسی دیگر می کند و باعث می شود برنامه نویسی در گو هم متفاوت از زبان‌های دیگر باشد. ممکن است برخی از نکات بالا را دوست نداشته باشید. اما ، اینطور نیست که شما نتوانید برنامه خود را بدون ویژگی های بالا بنویسید. تنها کاری که باید انجام دهید این است که 2-3 خط بیشتر بنویسید. اما در جنبه مثبت ، کدِ شما را تمیزتر می کند و وضوح بیشتری به کد شما می بخشد.

جایگاه زبان‌ها بر اساس کد خوانا در برابر کد بهینه
جایگاه زبان‌ها بر اساس کد خوانا در برابر کد بهینه

در نمودار بالا نمایش داده می شود که گو تقریباً به اندازه C/C ++ کارآمد است ، در حالی که syntax کد را مانند Ruby ، Python و سایر زبانها ساده نگه می‌دارد. این یک موقعیت برد-برد هم برای انسان‌ها و هم برای پردازنده‌ها است !!!

گو توسط Google پشتیبانی می‌شود.

  • من می دانم که این یک مزیت فنی نیست. اما ، گو توسط Google طراحی و پشتیبانی می شود. گوگل دارای یکی از بزرگترین زیرساخت های ابری در جهان است و به طور گسترده ای مقیاس بندی شده است. گو توسط گوگل برای حل مشکلات پشتیبانی از مقیاس پذیری و اثربخشی طراحی شده است. اینها همان مشکلاتی است که هنگام ایجاد سرورهای با آنها روبرو خواهینم شد.
  • گو همچنین توسط شرکت‌های بزرگ دیگر استفاده می‌شود که در لینک زیر می‌تونید اسامی برنامه‌ها شرکت‌ها و کاربرد استفاده ‌گو در آن را مطالعه کنید. (https://github.com/golang/go/wiki/GoUsers)

خلاصه:

گو عملکرد بسیار بالایی مثل زبان‌های C++/C, مدیریت Concurrency مثل جاوا و سیتنکس باحالی مثل پایتون و پرل داره. اگر برنامه ای برای یادگیری Go ندارید ، باز هم می گویم محدودیت سخت افزاری به ما ، توسعه دهندگان نرم افزار فشار می آورد تا کد فوق العاده کارآمدی (efficient) بنویسند. توسعه دهنده باید سخت افزار را بشناسد و برنامه خود را مطابق آن بهینه سازی کند. نرم افزار بهینه سازی شده می تواند بر روی سخت افزار ارزان تر و کندتر (مانند دستگاه های IOT) اجرا شود و در کل تأثیر بهتری بر تجربه کاربر نهایی بگذارد.

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

Rex Kerr:


گو جنبه های منفی زیادی نیز دارد که بیشتر آنها را به عنوان موارد مثبت ذکر کرده اید. این بدان معنا نیست که گو ارزش یادگیری ندارد (زبان سختی که نیست! چرا که نه!) ، اما این بدان معناست که پروژه های زیادی وجود دارد که نمی خواهید از گو برای آن استفاده کنید.

۱- گو مستقیماً بر روی سخت افزار اجرا می شود بدون اینکه نیاز باشه به سخت افزار کاری داشته باشید ، به طور متوسط ​​سریعتر از جاوا نیست (به benchmarkهای مختلف و Computer Languages Benchmark Game مراجعه کنید). اگر واقعاً می خواهید هر گونه عملکردی را روی سخت افزار خود انجام دهید ، باید از C ، C ++ ، Rust یا برخی از زبان های دیگر که کنترل مناسب را به شما می دهد ، استفاده کنید.

۲- قابلیت های abstraction گو عملاً وجود ندارد. شما می توانید از این زبان برای * انجام * کارها استفاده کنید اما نه برای ایجاد structureهای پیشرفته تر. نکته مثبت - فهم آسان آن است! نکته منفی - ساخت پروژه هایی با structure پیچیده برای همیشه دور از دسترس هستند ، زیرا ایجاد آنها بسیار دشوار است و کامپایلر به شما کمک نمی کند. در مقابل ، زبان هایی مانند C++ ، Scala ، Haskell و غیره مکانیسم های abstraction بسیار قدرتمندی را ارائه می دهند تا به کامپایلر شما بفهماند راه حل انتراعی شما برای مشکل پیچیده چیست تا کامپایلر به شما کمک کند.

۳- گو فقط دارای گوروتین برای همزمانی است. اگر مشکل شما با آن مدل Concurrency به خوبی حل شد ، عالی است! اگر نه ، خوب ، این تنها مدل شماست. سایر زبانها معمولاً ترکیبی از چنین مواردی را ارائه می دهند. گو گوروتین ها را به خوبی انجام می دهد ، بنابراین اغلب می توانید از آنها در مکانهایی استفاده کنید که فکر می کنید به چیز دیگری احتیاج دارید (به عنوان مثال در یک atomic reference).

بنابراین گو عملکردی در سطح جاوا (نه در سطح ++C) با یک رویکرد عالی برای Concurrency ، و زبانی جمع و جور ، مرتب و غیرقابل انعطاف را برای شما فراهم می کند. خوب!

پروژه های زیادی وجود دارد که دقیقاً گو همان چیزی است که شما می خواهید.