Saya mencoba menghasilkan string acak di Go dan di sini adalah kode yang saya tulis sejauh ini:
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
Implementasi saya sangat lambat. Pembibitan menggunakan time
nomor acak yang sama untuk waktu tertentu, sehingga loop berulang dan berulang. Bagaimana saya bisa meningkatkan kode saya?
Jawaban:
Setiap kali Anda mengatur seed yang sama, Anda mendapatkan urutan yang sama. Jadi tentu saja jika Anda menyetel seed ke waktu dalam loop cepat, Anda mungkin akan menyebutnya dengan seed yang sama beberapa kali.
Dalam kasus Anda, saat Anda memanggil
randInt
fungsi Anda hingga Anda memiliki nilai yang berbeda, Anda menunggu waktu (seperti dikembalikan oleh Nano) untuk berubah.Sedangkan untuk semua pseudo-random library , Anda harus menetapkan seed hanya sekali, misalnya saat menginisialisasi program Anda kecuali Anda secara khusus perlu mereproduksi urutan tertentu (yang biasanya hanya dilakukan untuk debugging dan pengujian unit).
Setelah itu Anda cukup menelepon
Intn
untuk mendapatkan bilangan bulat acak berikutnya.Pindahkan
rand.Seed(time.Now().UTC().UnixNano())
garis dari fungsi randInt ke awal main dan semuanya akan lebih cepat.Perhatikan juga bahwa saya pikir Anda dapat menyederhanakan pembuatan string:
sumber
rand.Seed(...)
fungsiinit()
.init()
dipanggil secara otomatis sebelumnyamain()
. Perhatikan bahwa Anda tidak perlu meneleponinit()
darimain()
!math/rand
tidak aman secara kriptografis. Jika itu merupakan persyaratan,crypto/rand
harus digunakan.Saya tidak mengerti mengapa orang menyemai nilai waktu. Ini dalam pengalaman saya tidak pernah menjadi ide bagus. Misalnya, sementara jam sistem mungkin direpresentasikan dalam nanodetik, presisi jam sistem bukanlah nanodetik.
Program ini tidak boleh dijalankan di taman bermain Go tetapi jika Anda menjalankannya di mesin Anda, Anda mendapatkan perkiraan kasar tentang jenis presisi yang dapat Anda harapkan. Saya melihat peningkatan sekitar 1000000 ns, jadi kenaikan 1 ms. Itu 20 bit entropi yang tidak digunakan. Sementara bit tinggi sebagian besar konstan.
Tingkat yang penting bagi Anda akan bervariasi tetapi Anda dapat menghindari jebakan nilai benih berdasarkan jam hanya dengan menggunakan
crypto/rand.Read
sumber sebagai sumber untuk benih Anda. Ini akan memberi Anda kualitas non-deterministik yang mungkin Anda cari dalam angka acak Anda (bahkan jika implementasi aktual itu sendiri terbatas pada serangkaian urutan acak yang berbeda dan deterministik).Sebagai catatan tetapi terkait dengan pertanyaan Anda. Anda dapat membuat sendiri
rand.Source
menggunakan metode ini untuk menghindari biaya memiliki kunci yang melindungi sumber. Therand
fungsi paket utilitas yang nyaman tetapi mereka juga menggunakan kunci di bawah tenda untuk mencegah sumber dari yang digunakan secara bersamaan. Jika Anda tidak membutuhkannya, Anda bisa menghindarinya dengan membuat milik Anda sendiriSource
dan menggunakannya secara tidak bersamaan. Terlepas dari itu, Anda TIDAK boleh me-reseed generator nomor acak Anda di antara iterasi, itu tidak pernah dirancang untuk digunakan seperti itu.sumber
hanya untuk membuangnya untuk anak cucu: kadang-kadang lebih disukai untuk menghasilkan string acak menggunakan string set karakter awal. Ini berguna jika string seharusnya dimasukkan secara manual oleh manusia; tidak termasuk 0, O, 1, dan l dapat membantu mengurangi kesalahan pengguna.
dan saya biasanya mengatur benih di dalam
init()
blok. Mereka didokumentasikan di sini: http://golang.org/doc/effective_go.html#initsumber
-1
dirand.Intn(len(alpha)-1)
. Ini karenarand.Intn(n)
selalu mengembalikan angka yang kurang darin
(dengan kata lain: dari nol hinggan-1
inklusif).-1
dalamlen(alpha)-1
akan menjamin bahwa angka 9 tidak pernah digunakan dalam urutan.OK kenapa begitu rumit!
Ini didasarkan pada kode dystroy tetapi cocok untuk kebutuhan saya.
Itu mati enam (rands ints
1 =< i =< 6
)Fungsi di atas adalah hal yang persis sama.
Saya harap informasi ini bermanfaat.
sumber
3 5 2 5 4 2 5 6 3 1
rand.Intn()
, jika tidak, Anda akan selalu mendapatkan nomor yang sama setiap kali Anda menjalankan program Anda.var bytes int
? Apa perbedaan untuk mengubah atasbytes = rand.Intn(6)+1
kebytes := rand.Intn(6)+1
? Mereka berdua sepertinya bekerja untuk saya, apakah salah satu dari mereka kurang optimal karena alasan tertentu?Ini nano detik, berapa peluang untuk mendapatkan seed yang sama dua kali.
Bagaimanapun, terima kasih atas bantuannya, inilah solusi akhir saya berdasarkan semua input.
sumber
what are the chances of getting the exact the exact same [nanosecond] twice?
Luar biasa. Itu semua tergantung pada ketepatan internal implementasi runtime golang. Meskipun unit adalah nano-detik, kenaikan terkecil mungkin satu mili detik atau bahkan satu detik.Jika tujuan Anda hanya untuk menghasilkan sengatan angka acak maka saya pikir tidak perlu menyulitkannya dengan beberapa panggilan fungsi atau mengatur ulang seed setiap waktu.
Langkah paling penting adalah memanggil fungsi seed sekali saja sebelum benar-benar berjalan
rand.Init(x)
. Seed menggunakan nilai seed yang disediakan untuk menginisialisasi Sumber default ke keadaan deterministik. Jadi, akan disarankan untuk memanggilnya sekali sebelum pemanggilan fungsi sebenarnya ke pseudo-random number generator.Berikut adalah contoh kode yang membuat string angka acak
Alasan saya menggunakan Sprintf adalah karena memungkinkan pemformatan string sederhana.
Juga, In
rand.Intn(7)
Intn mengembalikan, sebagai int, nomor pseudo-acak non-negatif dalam [0,7).sumber
@ [Denys Séguret] telah diposting dengan benar. Tetapi dalam kasus saya, saya perlu seed baru setiap kali karenanya di bawah kode;
Jika Anda membutuhkan fungsi cepat. Saya menggunakan seperti ini.
sumber
sumber
Pembaruan kecil karena perubahan golang api, harap hapus .UTC ():
waktu sekarang(). UTC () .UnixNano () -> waktu.Now (). UnixNano ()
sumber