كود Go الخاص بك يعمل ببطء؟ حان الوقت للنظر تحت الغطاء
\n\nلقد كتبت خدمة بلغة Go. إنها تعمل. ولكن عندما يصل الحمل إلى 10,000 طلب في الثانية، يبدأ الخادم في "الاختناق". موقف مألوف؟ تشتهر Go بأدائها "خارج الصندوق"، ولكن حتى في هذه اللغة الأنيقة هناك بعض المزالق. تسربات الغوروتين، إدارة غير فعالة للذاكرة، تخصيصات زائدة - كل هذا يقتل السرعة.
\n\nفي هذه المقالة، سنشرح كيف يساعد تحليل أداء Go في العثور على نقاط الضعف، وسنعرض تقنيات محددة لتحسين تطبيقات Go. ستتعلم كيفية استخدام الأدوات المدمجة pprof و go test -bench لتحويل تطبيقك إلى صاروخ. هيا بنا!
\n\nأدوات المحلل: pprof و trace
\n\nتوفر Go أداتين قويتين لتحليل الأداء: pprof (تحليل وحدة المعالجة المركزية، الذاكرة، الأقفال) و go tool trace (تحليل التزامن وأحداث جامع القمامة).
دمج pprof في خادم HTTP
\n\nأسهل طريقة لبدء التحليل هي إضافة net/http/pprof إلى خادمك. هذا يتطلب سطر استيراد واحد فقط:
import (\n _ "net/http/pprof"\n "net/http"\n)\n\nfunc main() {\n http.ListenAndServe(":8080", nil)\n}\n\nالآن، الملفات الشخصية متاحة على العنوان /debug/pprof/. لأخذ ملف تعريف لوحدة المعالجة المركزية لمدة 30 ثانية، قم بتنفيذ:
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=30\n\nبعد جمع البيانات، سيتم تشغيل وحدة تحكم تفاعلية. الأمر top15 سيظهر الوظائف الأكثر استهلاكًا:
(pprof) top15\nShowing nodes accounting for 3.50s, 87.50% of 4.00s total\n flat flat% sum% cum cum%\n 1.20s 30.00% 30.00% 1.50s 37.50% main.heavyComputation\n\nهل ترى main.heavyComputation؟ هذا هو مرشحنا للتحسين. للتصور، استخدم web (إذا كان Graphviz مثبتًا) - ستحصل على رسم بياني للاستدعاءات.
تحليل الذاكرة: البحث عن التسريبات
\n\nتسريبات الذاكرة في Go غالبًا ما تكون تسريبات غوروتين أو مراجع منسية لكائنات كبيرة. لنأخذ ملف تعريف الكومة:
\n\ngo tool pprof http://localhost:8080/debug/pprof/heap\n\nالأمر alloc_objects سيظهر أي الوظائف تنشئ أكبر عدد من الكائنات:
(pprof) alloc_objects\n 2.50GB 100% 100% 2.50GB 100% main.createLargeSlice\n\nهكذا وجدنا وظيفة تخصص 2.5 جيجابايت من الذاكرة! ربما يتم إنشاء شريحة ضخمة يمكن إعادة استخدامها باستخدام sync.Pool.
كتابة المعايير: خطوتك الأولى نحو التحسين
\n\nقبل التحسين، يجب القياس. معايير Go هي الأداة القياسية لقياس أداء الوظائف الفردية.
\n\nمثال: مقارنة دمج السلاسل النصية
\n\nلنفترض أننا ندمج سلاسل نصية في حلقة. الخيار السيئ:
\n\nfunc ConcatSlow(parts []string) string {\n result := ""\n for _, p := range parts {\n result += p\n }\n return result\n}\n\nالخيار الجيد هو استخدام strings.Builder:
func ConcatFast(parts []string) string {\n var b strings.Builder\n for _, p := range parts {\n b.WriteString(p)\n }\n return b.String()\n}\n\nلنكتب معيارًا (ملف concat_test.go):
func BenchmarkConcatSlow(b *testing.B) {\n parts := []string{"Hello", " ", "World", "!", " ", "From", " ", "Go"}\n for i := 0; i < b.N; i++ {\n ConcatSlow(parts)\n }\n}\n\nfunc BenchmarkConcatFast(b *testing.B) {\n parts := []string{"Hello", " ", "World", "!", " ", "From", " ", "Go"}\n for i := 0; i < b.N; i++ {\n ConcatFast(parts)\n }\n}\n\nنقوم بتشغيل:
\n\ngo test -bench=. -benchmem\n\nالنتيجة:
\n\nBenchmarkConc