Concurrent Write on stdout: Thread Safety Analysis
Dalam perbincangan baru-baru ini, sekeping kod Go telah dibentangkan yang mencetuskan perdebatan tentang urutan keselamatan apabila menulis secara serentak kepada stdout. Kod yang dimaksudkan ialah:
<code class="go">package main import ( "fmt" "os" "strings" ) func main() { x := strings.Repeat(" ", 1024) go func() { for { fmt.Fprintf(os.Stdout, x+"aa\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"bb\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"cc\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"dd\n") } }() <-make(chan bool) }</code>
Pertimbangan Keselamatan Benang:
Persoalan timbul sama ada kod ini selamat untuk benang apabila berbilang goroutin menulis kepada stdout serentak. Pelbagai sumber dan pendapat mengenai perkara itu disebut tetapi jawapan yang pasti tidak ditemui. Mari kita mendalami topik ini dengan lebih lanjut.
Gelagat Pakej fmt:
Fungsi pakej fmt hanya mengambil implementasi io.Writer dan panggil Write() padanya. Fungsi itu sendiri adalah selamat untuk benang, bermakna berbilang panggilan serentak ke fungsi fmt.F* adalah selamat. Walau bagaimanapun, pelaksanaan penulisan serentak kepada stdout bergantung pada "penulis" khusus yang digunakan.
Pelaksanaan "Penulis":
Dua kategori utama "penulis" adalah berkaitan :
Semantik POSIX:
Dalam kes deskriptor fail, POSIX memerlukan penulisan (2) panggilan menjadi atom apabila beroperasi pada fail biasa atau pautan simbolik. Ini bermakna dalam kes kami, di mana stdout diandaikan sebagai deskriptor fail, panggilan tulis hendaklah atom.
Perlaksanaan Perpustakaan Standard Go:
Pustaka standard Go pembalut di sekeliling deskriptor dan soket fail direka untuk memetakan operasi tulis 1-ke-1 kepada objek asas. Ini menghapuskan kemungkinan panggilan tulis dipecah atau dilekatkan bersama.
Kesimpulan:
Berdasarkan maklumat yang tersedia dan semantik asas panggilan tulis(2) POSIX , kod yang disediakan tidak tertakluk kepada perlumbaan data. Walau bagaimanapun, output yang ditulis kepada deskriptor fail asas mungkin dicampur dalam susunan yang tidak dapat diramalkan. Tingkah laku ini dipengaruhi oleh faktor seperti versi kernel OS, versi Go, perkakasan dan beban sistem.
Untuk memastikan bahawa output daripada setiap panggilan fmt.Fprint* tertentu muncul sebagai bahagian bersebelahan dalam output yang dihasilkan , adalah disyorkan untuk membuat siri panggilan menggunakan kunci atau menggunakan pakej log, yang menyediakan mekanisme pengunciannya sendiri.
Atas ialah kandungan terperinci Adakah Penulisan Serentak kepada `stdout` dalam Go Thread-Safe? Analisis Terperinci Kelakuan `fmt.Fprintf`.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!