Sobes.tech
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-ները տեղական կամ գլոբալ հերթից:

Աշխատանքի սկզբունքը՝

  1. Նոր gorutin-ը ստեղծվում է և տեղադրվում հասանելի P-ի տեղական հերթում:
  2. P-ի հետ կապված M-ը վերցնում է gorutin-ը տեղական հերթից և կատարում է այն:
  3. Եթե տեղական հերթը դատարկ է, M-ը փորձում է գողանալ gorutin-ներ այլ P-ներից:
  4. Եթե P-ը բլոկվում է (օրինակ՝ համակարգային կանչի ժամանակ), նրա հետ կապված M-ը անջատվում է, և այլ M միանում է այդ P-ին: Բլոկված M-ը կարող է կրկին օգտագործվել, երբ համակարգային կանչը ավարտվի:
  5. Եթե gorutin-ը բլոկվում է ալիքի կամ մյուտեքսի վրա, այն դրվում է սպասման հերթում, և պլանավորիչը ընտրում է այլ gorutin-՝ նույն M-ում կատարելու համար:
  6. Պլանավորիչը կատարում է պարբերական ստուգումներ՝ երկար ժամանակ աշխատող 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-ներ՝ համեմատած օպերացիոն համակարգի հոսքերի:
  • Պարզություն: ինտեգրված պլանավորումը լեզվում՝ դարձնելով հարթակային ծրագրավորումը ավելի մատչելի։