تتمثل إحدى العمليات الشائعة عند تطوير تطبيق Go ، أو قياسه لإيجاد طرق لتحسينه ، في قياس وقت تنفيذ الوظيفة. لقد قدمت موضوعوحدة المعالجة المركزية وتحديد سمات الذاكرة في Goبالفعل ، ولكن هذا مختلف وأكثر ملاءمة لقياس وقت تنفيذ الوظيفة المخصصة.
حدد الفاصل الزمني بين تعبيرين: استخدامtime.Since
time.Since
هي وظيفة يوفرهاtime
حزمة المكتبة القياسية التي تأخذ ملفTime
value ، وتحسب الفرق مع الوقت الحالي ، وترجع قيمةDuration
القيمة ، وهي نوع int64 بامتدادString()
الطريقة المرفقة ، والتي توفر تدوينًا وديًا للإنسان للوقت المحسوب.
import (
"fmt"
"time"
)
func main() {
start := time.Now()
<span style="color:#75715e">//... do something
fmt.Println(time.Since(start))
}
داخليا،time.Since
هو اختصار لtime.Now().Sub(t)
.
استخدامdefer
لقياس الوقت داخل دالة
يمكنك تجريد هذا باستخدامdefer
:
package main
import (
“log”
“time”
)
func runningtime(s string) (string, time.Time) {
log.Println("Start: ", s)
return s, time.Now()
}
func track(s string, startTime time.Time) {
endTime := time.Now()
log.Println("End: ", s, “took”, endTime.Sub(startTime))
}
func execute() {
defer track(runningtime(“execute”))
time.Sleep(3 * time.Second)
}
func main() {
execute()
}
قم بتحديد أداء الوظيفة من خلال تشغيلها عدة مرات: استخدم ملحقtesting
صفقة
هذه مكتبة بسيطة كتبتها ، تحسب عدد الأحرف الرونية في سلسلة.
runecount.go
package runecount
import “unicode/utf8”
func RuneCount(s string) int {
return len([]rune(s))
}
func RuneCount2(s string) int {
return utf8.RuneCountInString(s)
}
أي من طريقتين لحساب الأحرف الرونية في سلسلة أسرع؟ نكتشف من خلال كتابة معيار. تعيش المعايير في*_test.go
ملف ، مثل الاختبارات المنتظمة ، ويمكنه البقاء مع طرق الاختبار التي تبدأ بـTest*
، لكنهم يبدأون بـBenchmark*
بدلا من:
runecount_test.go
package runecount
import “testing”
func BenchmarkRuneCount(b testing.B) {
s := “Gophers are amazing 😁”
for i := 0; i < b.N; i++ {
RuneCount(s)
}
}
func BenchmarkRuneCount2(b testing.B) {
s := “Gophers are amazing 😁”
for i := 0; i < b.N; i++ {
RuneCount2(s)
}
}
أقوم بتشغيل هذا عن طريق التنفيذ ، في نفس المجلد حيث توجد الملفات:
go test -bench=.
هذا يتسبب في تشغيل جميع المعايير. لقد حصلت على ملف واحد فقط ، ولكن إذا كان لديك الكثير ، يمكنك تحديد الملف الذي تريد تشغيله.
يقوم كل معيار بتشغيل الحلقة التي تمر عبر متغير bN ، والذي يتم تحديده تلقائيًا بواسطة العداء القياسي ، حتى يصبح المتوسط مستقرًا بدرجة كافية لتحديد النتيجة.
هذا هو الناتج الذي أحصل عليه على جهاز Mac الخاص بي:
# flavio @ Flavios-MacBook-Pro in ~/go/src/github.com/flaviocopes/snippets/benchmark on git:master x [18:32:26]
$ go test -bench=.
BenchmarkRuneCount-2 20000000 115 ns/op
BenchmarkRuneCount2-2 30000000 44.1 ns/op
PASS
ok github.com/flaviocopes/snippets/benchmark 3.812s
20000000
و30000000
عدد العمليات التي يتم تشغيلها.
يقوم الأمر بإرجاع نتائج الاختبار: تم تشغيله 20 مليون مرةRuneCount()
، والتي استغرقت في المتوسط 163 نانوثانية ، ثم تم تشغيلها 30 مليون مرةRuneCount2()
، والتي استغرقت في المتوسط 74.2 نانوثانية لكل تكرار.
وبالتاليBenchmark1
الذي يعملRuneCount()
، أبطأ بمقدار 2x منRuneCount2()
، التي تستخدم المضمنةutf8.RuneCountInString
وظيفة. لا عجب هنا ، كماutf8.RuneCountInString
تم تحسينه بشكل كبير لهذه المهمة المحددة.
بدلا من استخدام ملفاتgo test
، يمكنك أيضًا الاتصالtesting.Benchmark
من أمر:
package main
import (
“fmt”
“testing”
“runecount”
)
func BenchmarkRuneCount(b testing.B) {
s := “Gophers are amazing 😁”
for i := 0; i < b.N; i++ {
RuneCount(s)
}
}
func BenchmarkRuneCount2(b testing.B) {
s := “Gophers are amazing 😁”
for i := 0; i < b.N; i++ {
RuneCount2(s)
}
}
func main() {
fmt.Println(testing.Benchmark(BenchmarkRuneCount))
fmt.Println(testing.Benchmark(BenchmarkRuneCount2))
}
أين تقرأ المزيد
- https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
- http://www.soroushjp.com/2015/01/27/beautifully-simple-benchmarking-with-go/
المزيد من دروس Go:
- استخدام وكيل NGINX العكسي لخدمة خدمات Go
- عمل نسخة من هيكل في Go
- أساسيات Go Web Server
- فرز نوع الخريطة في Go
- الذهاب المؤشرات باختصار
- وأوضح Go Tags
- الذهاب تنسيق التاريخ والوقت
- معالجة JSON باستخدام Go
- وظائف متنوعة
- ورقة الغش Go Strings
- شرح واجهة Go Empty
- تصحيح الأخطاء الذهاب مع VS Code و Delve
- تقوم Named Go بإرجاع المعلمات
- توليد أرقام وسلاسل عشوائية في Go
- بنية نظام الملفات لمشروع Go
- تم تنفيذ خوارزمية البحث الثنائي في Go
- استخدام إشارات سطر الأوامر في Go
- أوضح جوباته
- أنشئ تطبيق Command Line باستخدام Go: lolcat
- إنشاء أمر CLI باستخدام Go: cowsay
- استخدام أنابيب شل مع Go
- Go CLI التعليمي: Fortune clone
- ضع قائمة بالملفات في مجلد باستخدام Go
- استخدم Go للحصول على قائمة بالمستودعات من GitHub
- اذهب ، قم بإلحاق شريحة من السلاسل بملف
- اذهب ، قم بتحويل سلسلة إلى شريحة بايت
- تصور مساهمات Git المحلية الخاصة بك مع Go
- الشروع في استخدام Go CPU وتوصيف الذاكرة
- حل الخطأ "لا يدعم الفهرسة" في برنامج Go
- قياس وقت التنفيذ في برنامج Go
- بناء زاحف الويب باستخدام Go لاكتشاف العناوين المكررة
- Go Best Practices: المؤشر أم مستقبلات القيمة؟
- Go Best Practices: هل يجب عليك استخدام طريقة أم دالة؟
- Go Data Structures: Set
- ورقة الغش في خرائط Go
- إنشاء تطبيقات لأنواع عامة في Go
- Go Data Structures: القاموس
- Go هياكل البيانات: Hash Table
- تنفيذ مستمعي الأحداث في الانتقال عبر القنوات
- Go Data Structures: Stack
- Go هياكل البيانات: قائمة الانتظار
- Go Data Structures: Binary Search Tree
- Go هياكل البيانات: رسم بياني
- Go Data Structures: قائمة مرتبطة
- الدليل الكامل إلى Go Data Structures
- مقارنة قيم Go
- هل Go موجه للكائن؟
- العمل مع قاعدة بيانات SQL في Go
- استخدام متغيرات البيئة في Go
- Go البرنامج التعليمي: REST API مدعوم من PostgreSQL
- تمكين CORS على خادم Go Web
- نشر تطبيق Go في حاوية Docker
- لماذا Go هي لغة قوية للتعلم كمطور PHP
- اذهب ، قم بإزالة io.Reader.ReadString حرف سطر جديد
- اذهب ، كيف تراقب التغييرات وتعيد بناء برنامجك
- اذهب وعد الأشهر منذ تاريخ
- الوصول إلى معلمات HTTP POST في Go