Mengapa Go mempunyai model penjadualan GMP? Artikel berikut akan memperkenalkan kepada anda sebab mengapa terdapat model penjadualan GMP dalam bahasa Go. Saya harap ia akan membantu anda!
Model penjadualan GMP ialah intipati Go. Ia secara munasabah menyelesaikan masalah kecekapan coroutine penjadualan serentak berbilang benang.
Pertama sekali, kita mesti faham apa yang dimaksudkan oleh setiap generasi GMP.
Thread M setiap satu ditahan Apabila a pemproses P ingin mendapatkan coroutine, ia pertama kali diperoleh daripada P, jadi gambar rajah model GMP adalah seperti berikut:
Proses umum ialah benang M memperolehnya daripada P baris gilir Jika coroutine tidak dapat memperolehnya, ia akan bersaing untuk mendapatkan kunci daripada baris gilir global untuk mendapatkannya.
Struktur coroutine G dan benang M telah diterangkan dalam artikel sebelumnya Di sini kami menganalisis pemproses P.
Pemproses P menyimpan sekumpulan coroutine, supaya thread M boleh mendapatkan coroutine daripada mereka tanpa mengunci, tanpa perlu bersaing dengan thread lain untuk baris gilir global Coroutine dalam proses, dengan itu meningkatkan kecekapan penjadualan coroutine.
Kod sumber struktur p berada dalam srcruntimeruntime2.go
dan beberapa medan penting ditunjukkan di sini.
type p struct { ... m muintptr // back-link to associated m (nil if idle) // Queue of runnable goroutines. Accessed without lock. runqhead uint32 runqtail uint32 runq [256]guintptr runnext guintptr ... }
m
ialah urutan yang dimiliki oleh pemproses p
runq
ialah baris gilir runqhead
yang menyimpan. coroutines. runqtail
Mewakili penunjuk kepala dan ekor barisanrunnext
menunjuk ke coroutine boleh lari seterusnyaDalam srcruntimeproc.go
, terdapat kaedah schedule
, iaitu fungsi pertama yang dijalankan oleh benang. Dalam fungsi ini, utas perlu mendapatkan coroutine boleh laku Kodnya adalah seperti berikut:
func schedule() { ... // 寻找一个可运行的协程 gp, inheritTime, tryWakeP := findRunnable() ... }
func findRunnable() (gp *g, inheritTime, tryWakeP bool) { // 从本地队列中获取协程 if gp, inheritTime := runqget(pp); gp != nil { return gp, inheritTime, false } // 本地队列拿不到则从全局队列中获取协程 if sched.runqsize != 0 { lock(&sched.lock) gp := globrunqget(pp, 0) unlock(&sched.lock) if gp != nil { return gp, false, false } } }
Dapatkan coroutine daripada baris gilir tempatan
func runqget(pp *p) (gp *g, inheritTime bool) { next := pp.runnext // 队列中下一个可运行的协程 if next != 0 && pp.runnext.cas(next, 0) { return next.ptr(), true } ... }
Kemudian jika baris gilir tempatan dan Apakah yang perlu saya lakukan jika tiada coroutine dalam baris gilir global Patutkah kita membiarkan sahaja urutan terbiar?
Pada masa ini, pemproses P akan mencuri tugasan dan mencuri beberapa tugasan daripada baris gilir setempat bagi utas lain Ini dipanggil berkongsi tekanan utas lain dan meningkatkan penggunaan utasnya sendiri.
Kod sumber ada dalam srcruntimeproc.gostealWork
, anda boleh lihat jika anda berminat.
Adakah coroutine yang baru dibuat perlu diperuntukkan kepada baris gilir tempatan atau global Markah:
Proses sebenar ialah:
runnext
, yang bermaksud yang seterusnya akan dijalankan Coroutine ini melompat ke dalam baris gilirKod sumber berada dalam fungsi srcruntimeproc.gonewproc
.
// Create a new g running fn. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, gp, pc) // 创建新协程 pp := getg().m.p.ptr() runqput(pp, newg, true) // 寻找本地队列放入 if mainStarted { wakep() } }) }
Artikel ini pada mulanya memperkenalkan model penjadualan GMP dan memperincikan cara pemproses P dan benang M memperoleh coroutine.
Pemproses P menyelesaikan masalah pengecualian bersama berbilang benang untuk mendapatkan coroutine dan meningkatkan kecekapan penjadualan coroutine Walau bagaimanapun, tidak kira sama ada coroutine berada dalam baris gilir tempatan atau global, nampaknya ia hanya dilaksanakan secara berurutan. Jadi bagaimana dengan Go? Bagaimana untuk melaksanakan pelaksanaan coroutine tak segerak dan serentak? Mari kita sambung analisis dalam artikel seterusnya (walaupun tiada siapa yang akan membacanya...).
Pembelajaran yang disyorkan: Tutorial Golang
Atas ialah kandungan terperinci Analisis mendalam tentang sebab mengapa terdapat model penjadualan GMP dalam bahasa Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!