Gopher Academy
3.85K subscribers
933 photos
42 videos
280 files
2.19K links
🕸 Gopher Academy

🔷interview golang
https://github.com/mrbardia72/Go-Interview-Questions-And-Answers

حمایت مالی:
https://www.coffeete.ir/mrbardia72

ادمین:
@mrbardia72
Download Telegram
💋چی کار می‌کنه sync.Once

تضمین می‌کنه یک تابع دقیقاً یک‌بار اجرا بشه حتی اگر چندین goroutine هم‌زمان تلاش کنن اون رو اجرا کنن. متد اصلیش Do(f func()) هست: اولین فراخوانی Do تابع f را اجرا می‌کنه و فراخوانی‌های بعدی هیچ کاری نمی‌کنن (بلوک نمی‌شن؛ فقط بازمی‌گردن).

💋موارد متداول استفاده

* پیاده‌سازی Singleton (یک‌بار ساختن نمونهٔ مشترک).
* بارگذاری تنبل (lazy load) کانفیگ یا منابع سنگین فقط وقتی لازم شدن.
* عمل‌هایی که باید فقط یک‌بار انجام بشن (مثلاً ثبت یک handler، close ای که نباید دوباره انجام بشه، و غیره).

مثال ساده (Singleton)

var instance *MyType
var once sync.Once

func GetInstance() *MyType {
once.Do(func() {
instance = &MyType{ /* init */ }
})
return instance
}


مثال: امن کردن close یک channel`

var once sync.Once
var ch = make(chan struct{})

func safeClose() {
once.Do(func() { close(ch) })
}


💋 نکات و خطرات (خیلی مهم)

1. اگر تابعِ داخل `Do` پانیک کند: در نسخهٔ فعلیِ استاندارد، Do آن فراخوانی را «تمام‌شده» در نظر می‌گیرد — یعنی بعد از پانیک، فراخوانی‌های بعدی Do دیگر f را اجرا نخواهند کرد. (در عمل پانیک به caller برمی‌گردد ولی Once وضعیتِ «انجام‌شده» را علامت می‌زند). پس اگر f ممکن است پانیک کند یا نیاز به retry دارید، sync.Once ممکن است مناسبِ کامل نباشد.

> (نکته: در Go 1.21 به‌علاوه توابعی مثل OnceFunc / OnceValue اضافه شدند که رفتار پانیک/بازگردانی را متفاوت ارائه می‌دهند؛ خوب است اگر از این ورژن‌ها استفاده می‌کنید نگاهی به مستندات بیندازید).

2.ا `Once` را بعد از استفاده کپی نکنید — کپی کردن یک Once بعد از اولین استفاده خطا/رفتار غیرمنتظره ایجاد می‌کند.
3. تابعِ داخل `Do` نباید خودش `Do` را صدا بزند (یا باعث قفل/deadlock شود). اگر f در همان Once دوباره Do را فراخوانی کند، قفل/deadlock یا رفتار نامناسب ممکن است رخ دهد. (به‌صورت کلی از بلوک‌های طولانی یا عملیات که ممکن است بلوکه شوند داخل f خودداری کنید).

4. ا`Do` مقدار/خطا برنمی‌گرداند — اگر تابع شما ممکن است خطا داشته باشد و بخواهید آن را به callerها برگردانید، معمولاً از pattern زیر استفاده می‌کنند:

var once sync.Once
var cfg Config
var cfgErr error

func LoadConfig() error {
once.Do(func() {
cfg, cfgErr = loadFromDisk()
})
return cfgErr
}


اما دقت کنید: اگر loadFromDisk پانیک کند یا با خطاهای خاصی مواجه شود و شما نیاز به retry داشته باشید، این الگو کافی نیست چون Do بعد از اولین اجرا (حتی اگر پانیک شد) اجازهٔ تکرار نمی‌دهد.

💋 پیشنهاد وقتی می‌خواهید retry یا مقدار/خطای دقیق داشته باشید

اگر نیاز دارید تابع مقدار برگردونه و رفتارِ retry داشته باشید، باید از الگوهای دیگری استفاده کنید (مثلاً mutex + state machine، یا کانال‌ها، یا بسته‌های ثالث که این الگو رو پیاده‌سازی می‌کنن). در Go 1.21 توابعی مثل OnceValue هم اضافه شدند که کمک می‌کنند مقدار بازگردونده و رفتار پانیک مشخص‌تر بشه
21
Gopher Academy
💋چی کار می‌کنه sync.Once تضمین می‌کنه یک تابع دقیقاً یک‌بار اجرا بشه حتی اگر چندین goroutine هم‌زمان تلاش کنن اون رو اجرا کنن. متد اصلیش Do(f func()) هست: اولین فراخوانی Do تابع f را اجرا می‌کنه و فراخوانی‌های بعدی هیچ کاری نمی‌کنن (بلوک نمی‌شن؛ فقط بازمی‌گردن).…
بیایید هر دو حالت را ببینیم:
۱️⃣ نمونهٔ Retry‌دار (برای مواقعی که تابع ممکن است خطا بدهد)
۲️⃣ نمونهٔ واقعی‌تر (مثلاً بارگذاری فایل کانفیگ فقط یک‌بار)

---
🧩 مثال ۱: sync.Once با قابلیت Retry

sync.Once به‌صورت پیش‌فرض فقط یک‌بار اجرا می‌شود — حتی اگر اون اجرا شکست بخوره.
اما گاهی می‌خواهیم تابع فقط *در صورت موفقیت* «once» باشد، وگرنه دفعهٔ بعدی دوباره تلاش کند.
برای این کار، باید رفتار خودمان را روی Once شبیه‌سازی کنیم:

package main

import (
"errors"
"fmt"
"sync"
)

type OnceRetry struct {
mu sync.Mutex
done bool
}

func (o *OnceRetry) Do(f func() error) error {
o.mu.Lock()
defer o.mu.Unlock()

if o.done {
return nil
}

err := f()
if err != nil {
return err
}

o.done = true
return nil
}

func main() {
var once OnceRetry
counter := 0

task := func() error {
counter++
if counter < 3 {
fmt.Println(" Failed attempt", counter)
return errors.New("temporary error")
}
fmt.Println(" Success on attempt", counter)
return nil
}

for i := 0; i < 5; i++ {
err := once.Do(task)
if err != nil {
fmt.Println("Error:", err)
}
}

fmt.Println("Final counter =", counter)
}


🟢 نتیجه خروجی:

 Failed attempt 1
Error: temporary error
Failed attempt 2
Error: temporary error
Success on attempt 3
Final counter = 3


یعنی تابع تا زمانی که موفق نشده، باز هم قابل اجراست — اما بعد از موفقیت فقط یک‌بار انجام می‌شود

🧱 مثال ۲: بارگذاری فایل کانفیگ فقط یک‌بار (Real-world)

package main

import (
"encoding/json"
"fmt"
"os"
"sync"
)

type Config struct {
Port int `json:"port"`
Mode string `json:"mode"`
}

var (
cfg Config
cfgErr error
cfgOnce sync.Once
)

func LoadConfig() (Config, error) {
cfgOnce.Do(func() {
fmt.Println("📁 Reading config.json only once...")
data, err := os.ReadFile("config.json")
if err != nil {
cfgErr = err
return
}
cfgErr = json.Unmarshal(data, &cfg)
})
return cfg, cfgErr
}

func main() {
for i := 0; i < 3; i++ {
c, err := LoadConfig()
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Loaded config:", c)
}
}
}


🔹 حتی اگر LoadConfig() چندبار فراخوانی شود، فایل فقط یک‌بار خوانده می‌شود.
🔹 در برنامه‌های بزرگ (microserviceها، سرورها، یا SDKها) این pattern خیلی رایج است.
2🔥1
🔵 عنوان مقاله
Chans: Building Blocks for Idiomatic Go Pipelines

🟢 خلاصه مقاله:
** آنتون در مقاله «Chans: Building Blocks for Idiomatic Go Pipelines» بسته‌ی chans را معرفی می‌کند؛ مجموعه‌ای از عملگرهای عمومی و نوع‌امن روی channelها در زبان Go—مثل filter، map، partition و takeWhile—برای ساختpipelineهای همزمان به‌شکل idiomatic. این بسته با کاهش کد تکراری و افزایش ترکیب‌پذیری، نوشتن جریان‌های پردازش داده را ساده‌تر، خواناتر و قابل نگه‌داری‌تر می‌کند و برای پردازش جریان‌ها، رویدادها و کارهای IO-محور بسیار کاربردی است.

#Go #Concurrency #Channels #Pipelines #Generics #FunctionalProgramming #SoftwareEngineering

🟣لینک مقاله:
https://golangweekly.com/link/176627/web


👑 @gopher_academy
👍3
Gopher Academy
🔵 عنوان مقاله Chans: Building Blocks for Idiomatic Go Pipelines 🟢 خلاصه مقاله: ** آنتون در مقاله «Chans: Building Blocks for Idiomatic Go Pipelines» بسته‌ی chans را معرفی می‌کند؛ مجموعه‌ای از عملگرهای عمومی و نوع‌امن روی channelها در زبان Go—مثل filter،…
Here's a toy example:
// Given a channel of documents.
docs := make(chan []string, 10)
docs <- []string{"go", "is", "awesome"}
docs <- []string{"cats", "are", "cute"}
close(docs)

// Extract all words from the documents.
words := make(chan string, 10)
chans.Flatten(ctx, words, docs)
close(words)

// Calculate the total byte count of all words.
step := func(acc int, word string) int { return acc + len(word) }
count := chans.Reduce(ctx, words, 0, step)
fmt.Println("byte count =", count)

byte count = 22
👍2
Gopher Academy
📌 Memory Allocation in Go این پست اپدیت می‌شود 🔹 در این پست به بررسی جزئیات مدیریت حافظه در زبان Go می‌پردازیم. درک درست از ساختار حافظه به شما کمک می‌کند عملکرد برنامه‌هایتان را بهتر بهینه کنید و رفتار Garbage Collector را بهتر بفهمید. 🔵 Introduction…
این تصویر نمونه‌ای از مفهوم Summary برای یک bitmap در حافظه‌ی Go رو نشون می‌ده

🧩 این Bitmap Summary در مدیریت صفحات Go

در این شکل، هر بیت از bitmap نشان‌دهنده‌ی وضعیت یک صفحه‌ی حافظه است:

* 0 → صفحه آزاد (free)
* 1 → صفحه در حال استفاده (allocated)

برای بهینه‌سازی جستجوی صفحات آزاد، Go برای هر bitmap سه مقدار خلاصه‌شده (summary) نگه می‌داره:

* start = 3 → یعنی در ابتدای bitmap، ۳ صفحه‌ی متوالی آزاد داریم
* end = 7 → یعنی در انتهای bitmap، ۷ صفحه‌ی متوالی آزاد داریم
* max = 10 → طولانی‌ترین دنباله‌ی صفحات آزاد در کل bitmap برابر با ۱۰ صفحه است

🔹 فلش در تصویر جهت افزایش آدرس حافظه (از پایین به بالا) رو نشون می‌ده.
در نتیجه، ۳ صفحه‌ی آزاد در بخش پایین‌تر حافظه (low address) و ۷ صفحه‌ی آزاد در بالاترین بخش (high address) قرار دارن.

این ساختار باعث می‌شه Go خیلی سریع‌تر بتونه محدوده‌های بزرگ از صفحات آزاد رو پیدا کنه بدون این‌که کل bitmap رو اسکن کنه — فقط با نگاه کردن به summaryها!

👑 @gopher_academy
👍1🔥1
🔵 عنوان مقاله
progjpeg: image/jpeg But With Progressive Encoding Support

🟢 خلاصه مقاله:
progjpeg نسخه‌ای از بسته image/jpeg در زبان Go است که امکان Progressive Encoding را به آن اضافه می‌کند؛ قابلیتی که تصویر را ابتدا به‌صورت کم‌جزئیات نشان می‌دهد و در چند گذر با دریافت داده‌های بیشتر شفاف‌تر می‌شود. این ویژگی می‌تواند در شبکه‌های کند تجربه کاربری را بهبود دهد و توسط بیشتر مرورگرها و دیکدرهای تصویر پشتیبانی می‌شود. چون درخواست افزودن این قابلیت در مخزن رسمی Go «متوقف/فریز» شده بود، progjpeg این خلأ را برای توسعه‌دهندگان پر می‌کند. هرچند کاربرد آن تخصصی است، اما برای سرویس‌های وب و سامانه‌های سنگینِ تصویر می‌تواند تجربه بارگذاری روان‌تری فراهم کند، با درنظرگرفتن ملاحظاتی مثل پیچیدگی کدنویسی و تفاوت احتمالی در اندازه فایل.

#Go #Golang #JPEG #ProgressiveJPEG #ImageProcessing #WebPerformance #OpenSource

🟣لینک مقاله:
https://golangweekly.com/link/176639/web


👑 @gopher_academy
Clients should not be forced to depend on methods they do not use.


— Robert C. Martin (SOLID, interface segregation principle)
👍1