Middle+
Խոսեք Go-ում goroutine-ների պլանավորման մասին։
sobes.tech AI
Պատասխան AI-ից
Go լեզվի gorutin-ների պլանավորիչը օգտագործում է M:N մոդելը, որտեղ M gorutin-ները մապվում են N օպերացիոն համակարգի հոսքերի վրա: Այն արդյունավետ կերպով փոխում է gorutin-ները հոսքերի միջև, իրականացնելով անխափան բազմակատարություն (preemption points)՝ կանգառային կետերով:
GPM մոդելի հիմնական բաղադրիչները՝
- G (Goroutine): Կոդի կատարման միավորի ամփոփում, թեթև հոսք, որը կառավարում է Go պլանավորիչը:
- P (Processor): Լոգիկական պրոցեսոր, ներկայացնում է տեղական հերթի և ռեսուրսների կոնտեքստը՝ ինչպիսիք են մյուտեքսները և պլանավորիչը: P-ի քանակը ըստ նախնական սահմանման՝ որոշվում է պրոցեսորի լոգիկական միջուկների քանակով, բայց կարող է փոփոխվել
GOMAXPROCS-ով: - M (Machine/Thread): Օպերացիոն համակարգի հոսք, որը կատարում է կոդը: M-ն կապված է P-ի հետ և կատարում է gorutin-ները տեղական կամ գլոբալ հերթից:
Աշխատանքի սկզբունքը՝
- Նոր gorutin-ը ստեղծվում է և տեղադրվում հասանելի P-ի տեղական հերթում:
- P-ի հետ կապված M-ը վերցնում է gorutin-ը տեղական հերթից և կատարում է այն:
- Եթե տեղական հերթը դատարկ է, M-ը փորձում է գողանալ gorutin-ներ այլ P-ներից:
- Եթե P-ը բլոկվում է (օրինակ՝ համակարգային կանչի ժամանակ), նրա հետ կապված M-ը անջատվում է, և այլ M միանում է այդ P-ին: Բլոկված M-ը կարող է կրկին օգտագործվել, երբ համակարգային կանչը ավարտվի:
- Եթե gorutin-ը բլոկվում է ալիքի կամ մյուտեքսի վրա, այն դրվում է սպասման հերթում, և պլանավորիչը ընտրում է այլ gorutin-՝ նույն M-ում կատարելու համար:
- Պլանավորիչը կատարում է պարբերական ստուգումներ՝ երկար ժամանակ աշխատող gorutin-ների վրա, թույլ տալով մյուս gorutin-ներին ստանալ կատարողական ժամանակ:
Preemption points՝
- Ֆունկցիաների/մեթոդների կանչեր:
- Ցիկլեր, որոնք պարունակում են ֆունկցիայի կանչեր:
- Հիշողության բաժանում:
- Սինխրոնիզացիոն օբյեկտներ (ալիքներ, մյուտեքսներ):
Օրինակ՝ պլանավորումը՝
package main
import (
"fmt"
"runtime"
"time"
)
func worker(id int) {
fmt.Printf("Goroutine %d սկսեց աշխատանքը\n", id)
time.Sleep(time.Second) // Նման աշխատանք
fmt.Printf("Goroutine %d ավարտեց աշխատանքը\n", id)
}
func main() {
runtime.GOMAXPROCS(2) // Լրացուցիչ լոգիկական պրոցեսորների քանակը
for i := 1; i <= 5; i++ {
go worker(i) // Gorutin-ների ստեղծում
}
time.Sleep(3 * time.Second) // Գործողությունների ավարտին սպասում
fmt.Println("Հիմնական goroutine-ը ավարտվեց")
}
Այս օրինակով՝ 5 gorutin-ներ պլանավորվում են 2 լոգիկական պրոցեսորների վրա: Go պլանավորիչը կբաշխի այդ gorutin-ները հասանելի օպերացիոն համակարգի հոսքերի միջև՝ օգտագործելով տեղական և հնարավոր է՝ գլոբալ հերթեր, ինչպես նաև "գողության" մեխանիզմը:
Առավելություններ՝
- Մասշտաբելիություն: արդյունավետ օգտագործում բազմակողմանի համակարգերի:
- Նվազ ծախսեր: թեթև gorutin-ներ՝ համեմատած օպերացիոն համակարգի հոսքերի:
- Պարզություն: ինտեգրված պլանավորումը լեզվում՝ դարձնելով հարթակային ծրագրավորումը ավելի մատչելի։