ch
Feedback
Gopher Academy

Gopher Academy

前往频道在 Telegram
3 830
订阅者
+124 小时
+137
+1230
吸引订阅者
八月 '26
八月 '26
+61
在4个频道中
七月 '26
+58
在0个频道中
Get PRO
六月 '26
+67
在0个频道中
Get PRO
五月 '26
+45
在0个频道中
Get PRO
四月 '26
+24
在5个频道中
Get PRO
三月 '26
+10
在0个频道中
Get PRO
二月 '26
+79
在1个频道中
Get PRO
一月 '26
+29
在8个频道中
Get PRO
十二月 '25
+103
在7个频道中
Get PRO
十一月 '25
+72
在0个频道中
Get PRO
十月 '25
+598
在1个频道中
Get PRO
九月 '25
+61
在6个频道中
Get PRO
八月 '25
+84
在9个频道中
Get PRO
七月 '25
+99
在10个频道中
Get PRO
六月 '25
+47
在7个频道中
Get PRO
五月 '25
+45
在1个频道中
Get PRO
四月 '25
+63
在8个频道中
Get PRO
三月 '25
+90
在8个频道中
Get PRO
二月 '25
+91
在3个频道中
Get PRO
一月 '25
+96
在3个频道中
Get PRO
十二月 '24
+113
在7个频道中
Get PRO
十一月 '24
+94
在2个频道中
Get PRO
十月 '24
+116
在4个频道中
Get PRO
九月 '24
+138
在4个频道中
Get PRO
八月 '24
+101
在2个频道中
Get PRO
七月 '24
+187
在5个频道中
Get PRO
六月 '24
+173
在11个频道中
Get PRO
五月 '24
+301
在2个频道中
Get PRO
四月 '24
+185
在3个频道中
Get PRO
三月 '24
+172
在3个频道中
Get PRO
二月 '24
+154
在0个频道中
Get PRO
一月 '24
+207
在0个频道中
Get PRO
十二月 '23
+215
在4个频道中
Get PRO
十一月 '23
+77
在2个频道中
Get PRO
十月 '23
+79
在0个频道中
Get PRO
九月 '23
+70
在0个频道中
Get PRO
八月 '23
+108
在0个频道中
Get PRO
七月 '23
+68
在0个频道中
Get PRO
六月 '23
+106
在0个频道中
Get PRO
五月 '23
+211
在0个频道中
Get PRO
四月 '23
+142
在0个频道中
Get PRO
三月 '23
+56
在0个频道中
Get PRO
二月 '23
+70
在0个频道中
Get PRO
一月 '23
+62
在0个频道中
Get PRO
十二月 '22
+14
在0个频道中
Get PRO
十一月 '22
+24
在0个频道中
Get PRO
十月 '22
+15
在0个频道中
Get PRO
九月 '22
+78
在0个频道中
Get PRO
八月 '22
+47
在0个频道中
Get PRO
七月 '22
+36
在0个频道中
Get PRO
六月 '22
+26
在0个频道中
Get PRO
五月 '22
+27
在0个频道中
Get PRO
四月 '22
+14
在0个频道中
Get PRO
三月 '22
+21
在0个频道中
Get PRO
二月 '22
+13
在0个频道中
Get PRO
一月 '22
+24
在0个频道中
Get PRO
十二月 '21
+51
在0个频道中
Get PRO
十一月 '21
+107
在0个频道中
Get PRO
十月 '21
+13
在0个频道中
Get PRO
九月 '21
+31
在0个频道中
Get PRO
八月 '21
+29
在0个频道中
Get PRO
七月 '21
+41
在0个频道中
Get PRO
六月 '21
+29
在0个频道中
Get PRO
五月 '21
+26
在0个频道中
Get PRO
四月 '21
+49
在0个频道中
Get PRO
三月 '21
+376
在0个频道中
日期
订阅者增长
提及
频道
28 八月+1
27 八月+2
26 八月+1
25 八月+4
24 八月+3
23 八月+5
22 八月+2
21 八月+2
20 八月+3
19 八月+1
18 八月0
17 八月+1
16 八月+1
15 八月+3
14 八月0
13 八月+2
12 八月+3
11 八月+1
10 八月0
09 八月+1
08 八月+4
07 八月+3
06 八月+5
05 八月+6
04 八月0
03 八月+4
02 八月+1
01 八月+2
频道帖子
مراحل کار به این صورت است: ۱. پیدا کردن goroutineهای زنده ابتدا goroutineهای فعال، یعنی goroutineهای runnable یا running، به‌عنوان root در نظر گرفته می‌شوند. فعلاً goroutineهای blocked نادیده گرفته می‌شوند. ۲. ا Mark کردن حافظهٔ قابل‌دسترسی از rootها شروع می‌کنیم و pointerها را دنبال می‌کنیم تا مشخص شود کدام synchronization objectها، مانند channel یا WaitGroup، از این rootها قابل‌دسترسی هستند. ۳. بازگرداندن goroutineهای blocked به rootها تمام goroutineهای blocked بررسی می‌شوند. اگر goroutineای منتظر synchronization resourceای باشد که در مرحلهٔ قبل به‌عنوان reachable علامت‌گذاری شده است، آن goroutine نیز به مجموعهٔ rootها اضافه می‌شود. ۴. تکرار مراحل ۲ و ۳ تا زمانی تکرار می‌شوند که دیگر goroutine جدیدی که روی objectهای قابل‌دسترسی blocked باشد پیدا نشود. ۵. گزارش leakها در نهایت، هر goroutineای که همچنان در حالت blocked باقی مانده باشد، روی resourceای منتظر است که هیچ بخش فعال برنامه به آن دسترسی ندارد؛ بنابراین به‌عنوان leaked گزارش می‌شود. و profileِ goroutineleak هنوز Experimental است و برای فعال‌کردن آن باید هنگام build این گزینه را تنظیم کنید:
GOEXPERIMENT=goroutineleakprofile
فعال‌کردن این experiment باعث می‌شود این profile از طریق endpointهای net/http/pprof نیز در دسترس باشد:
/debug/pprof/goroutineleak
طبق گفتهٔ نویسندگان، پیاده‌سازی فعلی از نظر production آماده است. دلیل Experimental بودن آن بیشتر این است که تیم Go می‌خواهد دربارهٔ API بازخورد دریافت کند؛ به‌خصوص دربارهٔ اینکه این قابلیت به‌عنوان یک profile جدید در Go ارائه شود یا خیر.

2
🎖Goroutine Leak Profile نشت (Leak) زمانی اتفاق می‌افتد که یک یا چند goroutine برای مدت نامحدود روی synchronization primitiveهایی مانند channelها blocked بمانند، در حالی که goroutineهای دیگر همچنان در حال اجرا هستند و برنامه در مجموع به کار خود ادامه می‌دهد. یک مثال ساده: func leak() <-chan int { out := make(chan int) go func() { out <- 42 // leaks if nobody reads from out }() return out } اگر leak را فراخوانی کنیم اما از channel خروجی چیزی نخوانیم، goroutine داخلی leak برای باقی عمر برنامه هنگام تلاش برای ارسال داده به channel، blocked باقی می‌ماند: func main() { leak() // ... } برخلاف deadlock، نشت goroutine باعث panic نمی‌شود؛ بنابراین تشخیص آن بسیار دشوارتر است. همچنین برخلاف data race، ابزارهای Go برای مدت زیادی راهکار مستقیمی برای شناسایی این مشکل نداشتند. این وضعیت از Go 1.24 با معرفی package جدید synctest شروع به تغییر کرد. خیلی دربارهٔ آن صحبت نمی‌شود، اما synctest ابزار بسیار خوبی برای شناسایی leakها در زمان testing است. حالا Go 1.26 یک profile آزمایشی جدید به نام goroutineleak اضافه کرده که برای گزارش goroutineهای leaked در production طراحی شده است. برای مثال بالا می‌توانیم به شکل زیر از آن استفاده کنیم: func main() { prof := pprof.Lookup("goroutineleak") leak() time.Sleep(50 * time.Millisecond) prof.WriteTo(os.Stdout, 2) // ... } خروجی شامل یک goroutine stack trace مناسب خواهد بود که دقیقاً نشان می‌دهد leak در کجا اتفاق افتاده است. درواقعه goroutineleak چگونه leak را پیدا می‌کند؟ این profileِ goroutineleak برای پیدا کردن leakها از mark phase در Garbage Collector استفاده می‌کند تا مشخص کند کدام goroutineهای blocked همچنان به کد فعال برنامه متصل هستند. الگوریتم از goroutineهای runnable شروع می‌کند، تمام synchronization objectهایی را که از طریق آن‌ها قابل دسترسی هستند mark می‌کند و سپس هر goroutineِ blockedای را که روی یکی از آن objectها منتظر است، به مجموعهٔ rootها اضافه می‌کند. این فرآیند تا زمانی ادامه پیدا می‌کند که دیگر goroutine جدیدی پیدا نشود. در پایان، هر goroutineِ blocked که باقی مانده باشد، روی resourceای منتظر است که از هیچ بخش فعال برنامه قابل‌دسترسی نیست؛ بنابراین به‌عنوان leaked goroutine در نظر گرفته می‌شود. خلاصهٔ الگوریتم [ Start: GC mark phase ] │ │ 1. Collect live goroutines v ┌───────────────────────┐ │ Initial roots │ <────────────────┐ │ (runnable goroutines) │ │ └───────────────────────┘ │ │ │ │ 2. Mark reachable memory │ v │ ┌───────────────────────┐ │ │ Reachable objects │ │ │ (channels, mutexes) │ │ └───────────────────────┘ │ │ │ │ 3a. Check blocked goroutines │ v │ ┌───────────────────────┐ (Yes) │ │ Is blocked G waiting │ ─────────────────┘ │ on a reachable obj? │ 3b. Add G to roots └───────────────────────┘ │ │ (No - repeat until no new Gs found) v ┌───────────────────────┐ │ Remaining blocked │ │ goroutines │ └───────────────────────┘ │ │ 5. Report the leaks v [ LEAKED! ] (Blocked on unreachable synchronization objects)
125
3
🚀 Exploring Authorization with Go, OPA & Rego توی این ریپو که بیشتر جنبه یادگیری داره هدف اینه که منطق دسترسی کاربران رو از کد اصلی Go جدا کنیم و به یک Policy Engine بسپاریم. در این پروژه از: 🔹 گولنگ برای ساخت API 🔹از Open Policy Agent (OPA) برای اجرای Policy 🔹از Rego برای تعریف قوانین Authorization 🔹 از Regal برای Lint و بررسی کیفیت Policyها 🔹از OPA Test برای تست قوانین دسترسی 🔹از Makefile برای ساده‌تر کردن Development Workflow استفاده شده. مثلاً به‌جای اینکه داخل Go پر از شرط‌های مختلف داشته باشیم: if user.Role == "admin" { // ... } قوانین دسترسی را در Rego تعریف می‌کنیم: allow if { input.user.role == "manager" input.method == "POST" input.path == "/users" } و Go فقط تصمیم Policy Engine را مصرف می‌کند: HTTP Request ↓ Go ↓ OPA ↓ Rego ↓ Allow / Deny در حال حاضر پروژه شامل چندین API ساده هست (فقط برای درک درست نحوه ارتباط بک اند با policy rego فایل مون) مثل: GET /users POST /users DELETE /users GET /reports است و برای Roleهای مختلف مثل admin, manager و user تعریف شده. همچنین برای Policyها تست و lint داریم تا قوانین دسترسی قابل بررسی و maintainable باشند. 🎯 هدف این پروژه بیشتر از یک API ساده است؛ می‌خواهم در طول توسعه، مفاهیم Policy-Based Access Control، OPA، Rego و Authorization Architecture را به‌صورت عملی بررسی کنم. 🔗 GitHub: https://github.com/mrbardia72/labdon-opa اگر به Go، Backend Architecture، Authorization، OPA یا Rego علاقه دارید، خوشحال می‌شوم پروژه را ببینید و نظرتان را بگویید. 🙌
410
4
مدل ۲.۷۸ تریلیون پارامتری Kimi K3 رو فقط با C خالص روی یک CPU اجرا کردن بدون GPU، بدون PyTorch، بدون BLAS. فقط حدود ۸ گیگ رم. مهندسی‌ش دیوانه‌کننده‌ست. https://github.com/FareedKhan-dev/kimi-k3-in-c <Reza/>
326
5
درود و وقت بخیر دوستان 🌹 اگر مطالب کانال براتون مفیده، لطفاً با Boost کردن کانال از ما حمایت کنید. ❤️ با حمایت شما کمک می‌کنید کانال بیشتر دیده بشه و بتونیم محتوای بهتر و بیشتری در حوزه Golang و برنامه‌نویسی منتشر کنیم. پیشاپیش ممنون از حمایت و همراهی‌تون 🙏❤️ 👇 برای Boost کردن کانال https://t.me/boost/gopher_academy
314
6
sticker.webp
306
7
☝️ ویژگی‌های Go 1.26 رو از اینجا دنبال کنید. این پست به‌مرور به‌روزرسانی می‌شه و بعد از اون می‌ریم سراغ ویژگی‌های Go 1.27. و Go 1.27 هم از ۱۹ آگوست ۲۰۲۶ منتشر شده، پس بعد از تکمیل مرور 1.26، می‌تونیم بریم سراغ تغییرات نسخه جدید.
292
8
🎖Hybrid Public Key Encryption رمزنگاری ترکیبی با کلید عمومی (Hybrid Public Key Encryption) پکیج جدید crypto/hpke استاندارد Hybrid Public Key Encryption (HPKE) را مطابق با مشخصات RFC 9180 پیاده‌سازی می‌کند. این HPKE یک استاندارد نسبتاً جدید IETF برای رمزنگاری ترکیبی است. روش‌های سنتی رمزنگاری با کلید عمومی، مانند RSA، نسبتاً کند هستند و فقط می‌توانند حجم محدودی از داده را به‌صورت مستقیم رمزنگاری کنند. این HPKE با ترکیب دو نوع رمزنگاری این مشکل را برطرف می‌کند: از رمزنگاری نامتقارن (Asymmetric Cryptography)، یعنی public/private key، برای ایجاد امن یک shared secret استفاده می‌کند. سپس از رمزنگاری متقارن (Symmetric Encryption) که بسیار سریع‌تر است، برای محافظت از دادهٔ واقعی استفاده می‌کند. در نتیجه، می‌توان فایل‌ها یا پیام‌های حجیم را هم به‌صورت امن و هم با سرعت بالا رمزنگاری کرد، در حالی که مزایای امنیتی سیستم‌های مبتنی بر کلید عمومی نیز حفظ می‌شوند. بخش نامتقارن HPKE که KEM (Key Encapsulation Mechanism) نام دارد، می‌تواند هم از الگوریتم‌های سنتی، مانند الگوریتم‌های مبتنی بر elliptic curve، و هم از الگوریتم‌های جدید post-quantum مانند ML-KEM استفاده کند. این ML-KEM به‌گونه‌ای طراحی شده است که حتی در برابر کامپیوترهای کوانتومی آینده نیز امنیت خود را حفظ کند؛ کامپیوترهایی که ممکن است بتوانند رمزنگاری‌های سنتی را بشکنند.
274
9
rand.Int(rand.Reader, big.NewInt(10000)) هم می‌توان در محیط test، randomness را deterministic کرد. اگر موقتاً بخواهید رفتار قدیمی که به Reader ارائه‌شده احترام می‌گذاشت را برگردانید، می‌توانید هنگام اجرا این گزینه را تنظیم کنید: GODEBUG=cryptocustomrand=1 البته این گزینه قرار است در یکی از نسخه‌های آیندهٔ Go حذف شود.
209
10
🎖Reader-less Cryptography این APIهای فعلی cryptography، مانند ecdsa.GenerateKey یا rand.Prime، معمولاً یک io.Reader را به‌عنوان منبع دادهٔ تصادفی دریافت می‌کنند: // Generate a new ECDSA private key for the specified curve. key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) fmt.Println(key.D) // Generate a 64-bit integer that is prime with high probability. prim, _ := rand.Prime(rand.Reader, 64) fmt.Println(prim) این APIها تضمین نمی‌کنند که دقیقاً چگونه از byteهای تصادفی موجود در Reader استفاده خواهد شد. هر تغییری در الگوریتم‌های cryptographic داخلی می‌تواند ترتیب یا تعداد byteهایی را که از Reader خوانده می‌شوند تغییر دهد. در نتیجه، اگر کد application ــ حتی به‌اشتباه ــ به رفتار یک پیاده‌سازی مشخص در نسخهٔ X از Go وابسته باشد، ممکن است با رفتن به نسخهٔ X+1 خراب شود یا رفتار متفاوتی نشان دهد. تیم Go برای حل این مشکل تصمیم نسبتاً جسورانه‌ای گرفته است: اکنون بیشتر APIهای crypto، پارامتر io.Reader مربوط به randomness را نادیده می‌گیرند و همیشه از منبع تصادفی سیستم، یعنی crypto/internal/sysrand.Read، استفاده می‌کنند. بنابراین می‌توانید این APIها را بدون ارائهٔ Reader فراخوانی کنید و nil بدهید: // Generate a new ECDSA private key for the specified curve. key, _ := ecdsa.GenerateKey(elliptic.P256(), nil) fmt.Println(key.D) // Generate a 64-bit integer that is prime with high probability. prim, _ := rand.Prime(nil, 64) fmt.Println(prim) این تغییر روی APIهای زیر در subpackageهای crypto اعمال می‌شود: // crypto/dsa func GenerateKey(priv *PrivateKey, rand io.Reader) error // crypto/ecdh type Curve interface { GenerateKey(rand io.Reader) (*PrivateKey, error) } // crypto/ecdsa func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) // crypto/rand func Prime(rand io.Reader, bits int) (*big.Int, error) // crypto/rsa func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) اما ed25519.GenerateKey(rand) همچنان در صورتی که rand ارائه شود، از همان Reader استفاده می‌کند. اگر rand برابر nil باشد، این تابع به‌جای crypto/rand.Reader ــ که امکان override شدن دارد ــ از یک منبع امن داخلی برای تولید byteهای تصادفی استفاده می‌کند. تست deterministic برای cryptography برای پشتیبانی از تست‌های deterministic، یک package جدید به نام testing/cryptotest اضافه شده است که یک تابع به نام SetGlobalRandom دارد. این تابع برای مدت اجرای test، یک منبع global و deterministic برای randomness مربوط به cryptography تنظیم می‌کند: func Test(t *testing.T) { cryptotest.SetGlobalRandom(t, 42) // All test runs will generate the same numbers. p1, _ := rand.Prime(nil, 32) p2, _ := rand.Prime(nil, 32) p3, _ := rand.Prime(nil, 32) got := [3]int64{p1.Int64(), p2.Int64(), p3.Int64()} want := [3]int64{3713413729, 3540452603, 4293217813} if got != want { t.Errorf("got %v, want %v", got, want) } } در این مثال، هر بار test اجرا شود، همان sequence از اعداد تولید خواهد شد. این SetGlobalRandom روی crypto/rand و همچنین تمام sourceهای implicit مربوط به cryptographic randomness در packageهای crypto/* تأثیر می‌گذارد: func Test(t *testing.T) { cryptotest.SetGlobalRandom(t, 42) t.Run("rand.Read", func(t *testing.T) { var got [4]byte rand.Read(got[:]) want := [4]byte{34, 48, 31, 184} if got != want { t.Errorf("got %v, want %v", got, want) } }) t.Run("rand.Int", func(t *testing.T) { got, _ := rand.Int(rand.Reader, big.NewInt(10000)) const want = 6185 if got.Int64() != want { t.Errorf("got %v, want %v", got.Int64(), want) } }) } در نتیجه حتی در کدی مانند:
161
11
🎖Secret Mode پروتکل‌های رمزنگاری مانند WireGuard و TLS ویژگی‌ای به نام Forward Secrecy (محرمانگی پیشرو) دارند. منظور این است که حتی اگر مهاجم به secrets بلندمدت، مانند private key در TLS، دسترسی پیدا کند، نباید بتواند نشست‌های ارتباطی گذشته را رمزگشایی کند. برای دستیابی به این ویژگی، ephemeral keyها، یعنی کلیدهای موقتی که برای مذاکره و برقراری نشست استفاده می‌شوند، باید بلافاصله پس از handshake از حافظه حذف شوند. اگر راه قابل‌اعتمادی برای پاک‌سازی این حافظه وجود نداشته باشد، این کلیدها ممکن است برای مدت نامحدودی در حافظه باقی بمانند. مهاجمی که بعداً به آن‌ها دسترسی پیدا کند، می‌تواند دوباره session key را استخراج کرده و ترافیک گذشته را رمزگشایی کند؛ در نتیجه Forward Secrecy عملاً از بین می‌رود. در Go، مدیریت حافظه بر عهدهٔ runtime است و runtime به‌طور معمول تضمین نمی‌کند که حافظه دقیقاً چه زمانی و چگونه پاک شود. داده‌های حساس ممکن است در heap allocationها یا stack frameها باقی بمانند و از طریق مواردی مانند core dump یا حملات مستقیم به حافظه در معرض افشا قرار گیرند. به همین دلیل، توسعه‌دهندگان کتابخانه‌های رمزنگاری گاهی مجبور می‌شوند از راهکارهای غیرقابل‌اعتماد، مثلاً با استفاده از reflect، برای صفر کردن bufferهای داخلی استفاده کنند. با این حال، ممکن است بخشی از داده همچنان در نواحی‌ای از حافظه باقی بماند که توسعه‌دهنده امکان دسترسی یا کنترل مستقیم آن‌ها را ندارد. راهکار تیم Go برای این مشکل، package جدید runtime/secret است. این package اجازه می‌دهد یک function را در secret mode اجرا کنید. پس از پایان function، runtime بلافاصله registerها و stack مورد استفادهٔ آن را پاک‌سازی و صفر می‌کند. و Heap allocationهایی که function ایجاد کرده است نیز زمانی که Garbage Collector تشخیص دهد دیگر قابل دسترسی نیستند، پاک می‌شوند. secret.Do(func() { // Generate an ephemeral key and // use it to negotiate the session. }) این قابلیت کمک می‌کند داده‌های حساس بیشتر از زمان موردنیاز در حافظه باقی نمانند و در نتیجه، احتمال دسترسی مهاجم به آن‌ها کاهش پیدا کند. یک مثال واقعی‌تر 🔴 فرض کنید می‌خواهیم یک session key تولید کنیم، در حالی که ephemeral private key و shared secret را تا حد امکان ایمن نگه داریم: func DeriveSessionKey(peerPublicKey *ecdh.PublicKey) (*ecdh.PublicKey, []byte, error) { var pubKey *ecdh.PublicKey var sessionKey []byte var err error secret.Do(func() { privKey, e := ecdh.P256().GenerateKey(rand.Reader) if e != nil { err = e return } sharedSecret, e := privKey.ECDH(peerPublicKey) if e != nil { err = e return } sessionKey = performHKDF(sharedSecret) pubKey = privKey.PublicKey() }) return pubKey, sessionKey, err } در این مثال، ephemeral private key و raw shared secret عملاً مانند «پسماند سمی» هستند: برای تولید session key ضروری‌اند، اما نگه‌داشتن آن‌ها پس از استفاده خطرناک است. اگر این مقادیر در heap باقی بمانند و مهاجم بعدها به حافظهٔ application دسترسی پیدا کند ــ مثلاً از طریق یک core dump یا آسیب‌پذیری‌ای مانند و Heartbleed ــ می‌تواند از این داده‌های میانی برای استخراج مجدد session key استفاده کند و ارتباطات گذشته را رمزگشایی کند. با قرار دادن محاسبات داخل secret.Do، هدف این است که به‌محض ایجاد session key، مواد اولیهٔ مورد استفاده برای تولید آن پاک‌سازی شوند. در نتیجه، حتی اگر سرور در آینده compromise شود، این نشست مشخصِ گذشته نباید صرفاً به‌دلیل باقی‌ماندن این secrets در حافظه قابل افشا باشد؛ این همان چیزی است که به حفظ Forward Secrecy کمک می‌کند. برای نمونه:
208
12
آی بی ام اولین سلول‌های ماژولار فوق‌سرد کامپیوتر کوانتومی جدیدش رو به هم وصل کرد؛ قدمی به سمت کامپیوتر Starling که قراره تا ۲۰۲۹ ساخته بشه. همون سالی که گوگل هم برای فاصله‌گرفتن کامل از رمزنگاری فعلیش تعیین کرده. دلیلش Q-Day‌ه؛ روزی که کامپیوترهای کوانتومی اونقدر قوی بشن که بتونن رمزنگاری بانک، پیام‌رسان‌ها و اسناد دولتی رو بشکنن. NIST از همین حالا استانداردهای رمزنگاری مقاوم در برابر کوانتوم منتشر کرده و دولت‌ها دارن زیرساخت‌هاشون رو عوض می‌کنن. بعضی دولت‌ها همین الان دارن داده‌های رمزگذاری‌شده رو جمع‌آوری و ذخیره می‌کنن، بدون این‌که بتونن بازش کنن؛ فقط منتظرن یه کامپیوتر کوانتومی به‌اندازه‌ی کافی قوی ساخته بشه تا بازش کنن. یعنی هر اطلاعاتی که قراره سال‌ها محرمانه بمونه، از همین الان در خطره. https://newsroom.ibm.com/2026-08-19-ibm-connects-its-first-modular-cryogenic-systems-in-milestone-toward-fault-tolerant-quantum-computing https://ibm.com/quantum/blog/modular-cryogenics https://cnn.com/2026/05/17/science/quantum-computing-cybersecurity-q-day https://nist.gov/news-events/news/2024/08/nist-releases-first-3-finalized-post-quantum-encryption-standards https://paloaltonetworks.com/cyberpedia/what-is-q-day <^mad/>
352
13
واقعا Zed به شکل عجیبی سبک و عالیه، با rust توسعه داده شده اما برای رندر ui از ابزار های مرسوم مثل gtk استفاده نکرده و اومده GPUI رو خودش توسعه داده و معرفی کرده، من با Claude یک آپ با rust +GPUI ایجاد کردم و نتیجه فوق العاده بود، دقیقا سبک tailwind در وب رو منتقل کرده به rust تو توسعه دسکتاپ. جدیدا هم 30 میلیون جذب سرمایه داشته، و نکته جالب هم از نظر من اینه که توسعه دهنده Zed همون دولوپر atom هست، دقیقا پروژه که ای vscode اون رو fork می‌کنه و میشه یگانه ادیتور کد برای توسعه دهنده های جهان ولی خود atom که پلتفورم، اکستنشن ها و.. رو آورد هیچ جای از مارکت نبود. حالا با zed اومده تو مارکت و وقتی من پروژه رو بررسی کردم دقیقا فهمیدم این تیم به شدت کمال‌طلب هستند دیوانه وار خوب توسعه میدن مثلا واقعا می‌تونستم از gtk استفاده کنند چه دلیلی داره ui رندر ارائه میدیم.. ب نظرم بهترین می‌خوان باشن ولی یکی میاد فورک میگیره و می‌ره! https://zed.dev/ <MAHDI S. Homeyli/>
533
14
💼 به دنبال استخدام برنامه‌نویس هستید؟ یا به دنبال فرصت شغلی مناسب می‌گردید؟ 🟢 کارفرمایان: اگر به دنبال جذب برنامه‌نویس هستید، آگهی استخدام خود را برای ما ارسال کنید تا منتشر شود. 🟢 کارجویان: اگر به دنبال فرصت شغلی هستید، رزومه خود را برای ما ارسال کنید تا در صورت وجود موقعیت مناسب، به شرکت‌ها و کارفرمایان معرفی شوید. 🚀 👤 ادمین: @mrbardia72 📄 لطفاً موارد زیر را به همراه فایل PDF رزومه ارسال کنید: ✅ نام و نام خانوادگی (اجباری) ✅ سابقه کار (اجباری) ✅ محل سکونت (اجباری) ✅ امکان نقل مکان برای کار (اجباری) 🔹 لینک LinkedIn (اختیاری) 🔹 لینک GitHub (اختیاری)
490
15
🔴 دلار : ۲۰۰ هزار و ۸۰۰ تومن!🫤😳🥶🤬
544
16
یک جمله‌ی خیلی خوب برای به خاطر سپردن تفاوت بین Data Race و Race Condition در واقعه Data Race درباره‌ی "هم‌زمانی دسترسی به داده" است؛ و Race Condition درباره‌ی "وابستگی نتیجه به ترتیب اجرا" است. و نکته‌ی مهم در Go اینه که Race Detector (-race) عمدتاً Data Race را پیدا می‌کند، نه تمام Race Conditionهای منطقی برنامه.
556
17
قضیه این Jump Table چیه که توی کامپایلر گو ازش استفاده می کنن؟ تکنیک/ساختار برای اجرای سریع‌تر شاخه‌های مختلف کده، و در بحث compiler / assembly / runtime هست. خیلی ساده: فرض کن اینو داری: switch x { case 0: foo() case 1: bar() case 2: baz() case 3: qux() } یک روش ساده اینه که کامپایلر کلی if یا مقایسه پشت‌سرهم بسازه: if x == 0 → foo else if x == 1 → bar else if x == 2 → baz else if x == 3 → qux ولی اگر caseها پشت‌سرهم و متراکم باشن، می‌شه یک آرایه از آدرس مقصدها داشت: jump_table: [0] → address of foo [1] → address of bar [2] → address of baz [3] → address of qux بعد تقریباً این اتفاق می‌افته: x │ ├── bounds check │ └── jump_table[x] │ ├── 0 → foo ├── 1 → bar ├── 2 → baz └── 3 → qux یعنی به‌جای اینکه بگه: x == 0 ? x == 1 ? x == 2 ? x == 3 ? مستقیم میره سراغش: jump_table[x] 🫤چرا به درد می‌خوره؟ مهم‌ترین کاربردش سریع کردن dispatch ـه؛ یعنی وقتی یک مقدار تعیین می‌کنه کدوم مسیر باید اجرا بشه. مثلاً: switchهای بزرگ ماشین حالت (state machine) interpreterها VMها opcode dispatch بعضی parserها compiler-generated code مثلاً یک interpreter ممکنه opcode داشته باشه: 0 → ADD 1 → SUB 2 → MUL 3 → DIV 4 → LOAD 5 → STORE به‌جای اینکه برای هر opcode کلی مقایسه انجام بده، می‌تونه از jump table استفاده کنه: opcode = 4 ↓ jump_table[4] ↓ LOAD handler ولی همیشه استفاده نمی‌شه این نکته مهمه. اگر caseها پراکنده باشن: switch x { case 10: case 1000: case 999999: } ساختن jump table می‌تونه خیلی پرمصرف از نظر حافظه باشه؛ چون باید بین 10 تا 999999 کلی slot داشته باشی. در این شرایط compiler ممکنه از روش‌های دیگه مثل binary search یا مقایسه‌های زنجیره‌ای استفاده کنه. پس به‌صورت خیلی خلاصه:👇📣🕊 Jump table = تبدیل یک انتخاب بین چند مسیر به یک lookup + jump مستقیم. و نکته جالبش اینه که وقتی توی Go داری assembly یا خروجی compiler رو نگاه می‌کنی، ممکنه چیزی ببینی که ظاهراً خیلی عجیب‌تر از switch معمولی Go باشه؛ چون compiler بر اساس تعداد و توزیع caseها تصمیم می‌گیره بهترین روش dispatch چی باشه. @gopher_academy @gopher_academy @gopher_academy @gopher_academy
666
18
goos: linux goarch: amd64 cpu: AMD EPYC 9575F 64-Core Processor BenchmarkAddPlain/1k-2 1517698 889.9 ns/op 13808.74 MB/s BenchmarkAddPlain/65k-2 23448 52613 ns/op 14947.46 MB/s BenchmarkAddPlain/1m-2 2047 1005628 ns/op 11932.84 MB/s BenchmarkAddSIMD/1k-2 36594340 33.58 ns/op 365949.74 MB/s BenchmarkAddSIMD/65k-2 410742 3199 ns/op 245838.52 MB/s BenchmarkAddSIMD/1m-2 12955 94228 ns/op 127351.33 MB/s این نتایج نشان می‌دهند که در این benchmark، نسخهٔ SIMD نسبت به پیاده‌سازی plain بهبود بسیار چشمگیری دارد؛ هرچند میزان واقعی این بهبود به workload، معماری CPU و الگوی دسترسی به حافظه وابسته است. این پکیج هنوز experimental است و برای فعال‌کردن آن باید هنگام build گزینهٔ زیر را تنظیم کنید: GOEXPERIMENT=simd
264
19
🎖Vectorized Operations پکیج جدید simd/archsimd دسترسی به عملیات وکتوری‌شدهٔ وابسته به معماری (SIMD — Single Instruction, Multiple Data) را فراهم می‌کند. این یک پکیج low-level است که قابلیت‌های وابسته به سخت‌افزار را مستقیماً در اختیار برنامه‌نویس قرار می‌دهد. در حال حاضر فقط از پلتفرم‌های amd64 پشتیبانی می‌کند. از آنجا که معماری‌های مختلف CPU مجموعهٔ بسیار متفاوتی از عملیات SIMD دارند، طراحی یک API واحد و قابل‌حمل که روی همهٔ آن‌ها کار کند دشوار است. بنابراین تیم Go تصمیم گرفته ابتدا با یک API سطح پایین و وابسته به معماری شروع کند تا کاربران حرفه‌ای (power users) بتوانند بلافاصله به قابلیت‌های SIMD روی رایج‌ترین پلتفرم سرورها، یعنی amd64، دسترسی داشته باشند. این پکیج نوع‌های وکتوری را به‌صورت struct تعریف می‌کند؛ برای مثال: Int8x16 — یک وکتور SIMD با عرض ۱۲۸ بیت شامل شانزده عدد صحیح ۸ بیتی Float64x8 — یک وکتور SIMD با عرض ۵۱۲ بیت شامل هشت مقدار floating-point شصت‌وچهار بیتی این نوع‌ها با vector registerهای سخت‌افزار مطابقت دارند. پکیج از وکتورهایی با عرض ۱۲۸، ۲۵۶ و ۵۱۲ بیت پشتیبانی می‌کند. بیشتر عملیات به‌صورت method روی نوع‌های وکتوری تعریف شده‌اند و معمولاً مستقیماً به instructionهای سخت‌افزار نگاشت می‌شوند؛ یعنی عملاً overhead اضافی ندارند. برای دیدن نحوهٔ استفاده، تابع زیر را در نظر بگیرید که با استفاده از SIMD، دو وکتور float32 را با هم جمع می‌کند: func Add(a, b []float32) []float32 { if len(a) != len(b) { panic("slices of different length") } // If AVX-512 isn't supported, fall back to scalar addition, // since the Float32x16.Add method needs the AVX-512 instruction set. if !archsimd.X86.AVX512() { return fallbackAdd(a, b) } res := make([]float32, len(a)) n := len(a) i := 0 // 1. SIMD loop: Process 16 elements at a time. for i <= n-16 { // Load 16 elements from a and b vectors. va := archsimd.LoadFloat32x16Slice(a[i : i+16]) vb := archsimd.LoadFloat32x16Slice(b[i : i+16]) // Add all 16 elements in a single instruction // and store the results in the result vector. vSum := va.Add(vb) // translates to VADDPS asm instruction vSum.StoreSlice(res[i : i+16]) i += 16 } // 2. Scalar tail: Process any remaining elements (0-15). for ; i < n; i++ { res[i] = a[i] + b[i] } return res } در این پیاده‌سازی، اگر CPU از AVX-512 پشتیبانی نکند، تابع به پیاده‌سازی scalar یعنی fallbackAdd برمی‌گردد؛ زیرا متد Float32x16.Add به instruction set مربوط به AVX-512 نیاز دارد. در حلقهٔ SIMD، در هر iteration تعداد ۱۶ عنصر به‌صورت هم‌زمان پردازش می‌شود. در نتیجه: vSum := va.Add(vb) هر ۱۶ مقدار را با یک instruction جمع می‌کند و این عملیات به instruction اسمبلی VADDPS نگاشت می‌شود. سپس اگر در انتهای آرایه بین ۰ تا ۱۵ عنصر باقی بماند، این عناصر در بخش scalar tail و به‌صورت معمولی پردازش می‌شوند. برای مثال، می‌توانیم آن را روی دو وکتور اجرا کنیم: func main() { a := []float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17} b := []float32{17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1} res := Add(a, b) fmt.Println(res) } عملیات رایج در پکیج archsimd شامل موارد زیر است: Load / Store: بارگذاری وکتور از array/slice یا ذخیرهٔ وکتور در array/slice Arithmetic: Add، Sub، Mul، Div، DotProduct Bitwise: And، Or، Not، Xor، Shift Comparison: Equal، Greater، Less، Min، Max Conversion: As، SaturateTo، TruncateTo Masking: Compress، Masked، Merge Rearrangement: Permute این پکیج فقط از instructionهای AVX استفاده می‌کند و SSE را به کار نمی‌گیرد. Benchmark در یک benchmark ساده برای جمع دو وکتور، هر دو پیاده‌سازی plain و SIMD از sliceهای ازپیش‌تخصیص‌یافته استفاده می‌کنند: 👇👇👇👇👇
248
20
🎖Faster Memory Allocation در runtime زبان Go اکنون برای اشیای کوچک، از ۱ تا ۵۱۲ بایت، نسخه‌های تخصصی‌شده‌ای از تابع تخصیص حافظه دارد. برای انتخاب سریع تابع مناسب بر اساس اندازه، از jump table استفاده می‌شود؛ به‌جای اینکه همهٔ تخصیص‌ها صرفاً از یک پیاده‌سازی عمومی عبور کنند. در یادداشت‌های انتشار Go آمده است که «compiler اکنون فراخوانی‌هایی را برای routineهای تخصیص حافظهٔ تخصصی‌شده بر اساس اندازه تولید می‌کند». اما بر اساس کد منبع، این بیان کاملاً دقیق نیست: compiler همچنان فراخوانی‌هایی به تابع عمومی mallocgc تولید می‌کند. سپس mallocgc در runtime این فراخوانی‌ها را به توابع جدید و تخصصی‌شدهٔ تخصیص حافظه dispatch می‌کند. این تغییر، هزینهٔ تخصیص حافظه برای اشیای کوچک را تا ۳۰٪ کاهش می‌دهد. تیم Go انتظار دارد بهبود کلی در برنامه‌های واقعی که allocation سنگینی دارند، حدود ۱٪ باشد. من نتوانستم benchmark موجودی برای این تغییر پیدا کنم، بنابراین benchmark خودم را ایجاد کردم. نتیجه هم واقعاً نشان می‌دهد که اجرای آن روی Go 1.25 در مقایسه با Go 1.26 بهبود قابل‌توجهی دارد: goos: darwin goarch: arm64 cpu: Apple M1 │ go1_25.txt │ go1_26.txt │ │ sec/op │ sec/op vs base │ Alloc1-8 8.190n ± 6% 6.594n ± 28% -19.48% (p=0.011 n=10) Alloc8-8 8.648n ± 16% 7.522n ± 4% -13.02% (p=0.000 n=10) Alloc64-8 15.70n ± 15% 12.57n ± 4% -19.88% (p=0.000 n=10) Alloc128-8 56.80n ± 4% 17.56n ± 4% -69.08% (p=0.000 n=10) Alloc512-8 81.50n ± 10% 55.24n ± 5% -32.23% (p=0.000 n=10) geomean 21.99n 14.33n -34.83% پیاده‌سازی جدید به‌صورت پیش‌فرض فعال است. اگر بخواهید آن را غیرفعال کنید، هنگام build این گزینه را تنظیم کنید: GOEXPERIMENT=nosizespecializedmalloc البته انتظار می‌رود این گزینه در Go 1.27 حذف شود.
185