Hello Gophers ?
Dalam catatan blog ini, saya akan menunjukkan kepada anda cara menggunakan alat hebat yang terbina dalam pakej ujian #golang. Bagaimanakah anda akan menguji prestasi sekeping kod atau fungsi? Gunakan ujian penanda aras.
Jom.
Untuk ujian ini, saya akan menggunakan Nombor Fibonacci klasik atau Jujukan Fibonacci, yang ditentukan oleh:
if (x < 2) F(0) = 1 F(2) = 2 else F(x) = F(x-1) + F(x-2) In practice, the sequence is: 1, 1, 2, 3, 5, 8, 13, etc.
Jujukan ini penting kerana ia muncul dalam beberapa bahagian matematik dan alam semula jadi, seperti yang ditunjukkan di bawah:
Terdapat beberapa cara untuk melaksanakan kod ini dan saya akan memilih dua untuk ujian penanda aras kami: kaedah rekursif dan berulang untuk mengiranya. Objektif utama fungsi adalah untuk menyediakan kedudukan dan mengembalikan nombor Fibonacci pada kedudukan itu.
// main.go func fibRecursive(n int) int { if n <= 2 { return 1 } return fibRecursive(n-1) + fibRecursive(n-2) }
// main.go func fibIterative(position uint) uint { slc := make([]uint, position) slc[0] = 1 slc[1] = 1 if position <= 2 { return 1 } var result, i uint for i = 2; i < position; i++ { result = slc[i-1] + slc[i-2] slc[i] = result } return result }
Kaedah ini tidak dioptimumkan, tetapi keputusan ujian adalah berbeza dengan ketara walaupun untuk bilangan yang kecil. Anda akan melihat ini dalam ujian. Untuk mengikuti kod tersebut, anda boleh klik di sini.
Sekarang, untuk ujian penanda aras, mari tulis beberapa ujian dalam fail _main_test.go. Menggunakan dokumentasi Golang pada penanda aras, anda boleh mencipta fungsi untuk diuji seperti berikut:
// main_test.go // The key is to start every function you want to benchmark with the keyword Benchmark and use b *testing.B instead of t *testing.T as input func BenchmarkFibIterative(b *testing.B) { // Use this for-loop to ensure the code will behave correctly. // Now, you can put the function or piece of code you want to test for i := 0; i < b.N; i++ { fibIterative(uint(100)) } } // Same as above func BenchmarkFibRecursive(b *testing.B) { for i := 0; i < b.N; i++ { fibRecursive(100) } }
Soalan, sebelum anda meneruskan: yang manakah lebih cepat?
Mari kita jalankan ujian untuk nombor yang kecil (10) dan untuk nombor yang lebih besar sedikit (80). Untuk menjalankan ujian penanda aras, anda hanya jalankan arahan:
pergi ujian -bench=NameoftheFunction
Jika anda ingin mengetahui lebih lanjut tentang arahan ini, semak di sini.
Ujian pertama: kedudukan=10
//(fibIterative) Results: cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 24491042 42.50 ns/op PASS ok playground 1.651s
Mari kita analisis dengan bantuan imej ini:
Menurut imej, kami mempunyai 8 teras untuk ujian, tiada had masa (ia akan berjalan sehingga selesai). Ia mengambil masa 1.651s untuk menyelesaikan tugasan itu.
==== Extra ==== We got 24,491,042 iterations (computations), and each iteration (op) took 42.50 ns. Doing some math, we can calculate how much time one op took: 42.50 ns/op with 1 ns = 1/1,000,000,000 s op ≈ 2.35270590588e-12 s ==== Extra ====
Itu keputusan yang baik. Mari semak fungsi rekursif untuk kedudukan 10:
// Results BenchmarkFibRecursive-8 6035011 187.8 ns/op PASS ok playground 1.882s
Kita dapat lihat bahawa ia mengambil masa 1.882s untuk menyelesaikan tugas itu.
Fungsi berulang dimenangi beberapa saat. Mari cuba satu lagi ujian dengan:
Kedudukan 50
// Results for the Iterative Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 27896118 45.37 ns/op PASS ok playground 2.876s // Results for the Recursive Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibRecursive-8 6365198 186.3 ns/op PASS ok playground 1.918s
Wah! Kini fungsi rekursif lebih pantas?
Mari kita selesaikan dengan nombor yang lebih besar sedikit.
Kedudukan 80
// Results for the Iterative Function cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibIterative-8 5102344 229.5 ns/op PASS ok playground 1.933s // Results for the Recursive Function // My poor PC couldn’t handle it, so I had to reduce the position to 50 just to get some results printed. cpu: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz BenchmarkFibRecursive-8 1 44319299474 ns/op PASS ok playground 44.951s
Perbezaan sangat besar. Untuk kedudukan 80, pendekatan berulang mengambil masa kira-kira 2 saat. Untuk kedudukan 50, fungsi rekursif mengambil masa sekitar 45 saat. Ini menunjukkan kepentingan menanda aras kod anda apabila projek Golang anda mula perlahan.
Jika kod pengeluaran anda berjalan perlahan atau lebih perlahan tanpa diduga, anda boleh menggunakan teknik ini, digabungkan dengan pprof atau alatan lain daripada pakej ujian terbina dalam, untuk mengenal pasti dan menguji prestasi kod anda kurang baik dan cara mengoptimumkannya.
Nota sampingan: tidak semua kod yang cantik di mata adalah lebih berprestasi.
Bolehkah anda mencari cara yang lebih baik untuk meningkatkan fungsi rekursif? (Petua: gunakan Pengaturcaraan Dinamik). Artikel ini menerangkan sebab untuk beberapa nombor kecil, strategi rekursif adalah lebih baik.
Atas ialah kandungan terperinci Penanda aras dengan Golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!