Sobes.tech
Middle

Какво е време за изпълнение (runtime) и как работи планировчикът (scheduler)?

sobes.tech AI

Отговор от AI

Времето за изпълнение (runtime) в Go е средата, в която се изпълняват програмите на Go. Тя включва:

  • Управление на паметта: Събирачът на отпадъци (garbage collector) автоматично управлява разпределението и освобождаването на памет.
  • Планировчик (scheduler): Управлява изпълнението на goroutine-ите върху нишки на операционната система.
  • Системни извиквания: Предоставя интерфейс за взаимодействие с операционната система.
  • Примитиви за синхронизация: Канали, мютекси и други механизми за координация на goroutine-ите.

Планировчикът на Go реализира модел M:N (множество goroutine-и върху множество нишки на ОС). Основните му компоненти:

  • G (Goroutine): Лека нишка за изпълнение, по същество абстракция над функция.
  • M (Machine): Нишка на операционната система, върху която се изпълняват програмите на Go.
  • P (Processor): Логически процесор, свързан с нишка на ОС. Той държи локална опашка runnable за goroutine-и.

Принцип на работа на планировчика:

  1. Goroutine-ите (G) се създават и добавят към глобална или локална опашка runnable.
  2. ОС нишките (M) се асоциират с логически процесори (P). Броят на P по подразбиране е равен на броя ядра CPU (GOMAXPROCS).
  3. P взема goroutine от своята локална опашка. Ако локалната опашка е празна, P се опитва да "краде" (steal) goroutine-и от опашката на друг P или от глобалната опашка.
  4. M изпълнява goroutine.
  5. Когато goroutine блокира (например, при четене от канал без данни или при системно извикване), M се отделя от P, и P става достъпен за изпълнение на друга goroutine. Блокираната goroutine се поставя в очакване. Когато блокирането бъде премахнато, goroutine-ът отново става runnable и се връща в опашката.
  6. Ако M блокира в системно извикване, той не държи P. Може да бъде създадено ново M или използвано съществуващо, за да може P да продължи изпълнението на други goroutine-и.

Този подход позволява ефективно използване на ресурсите на процесора и лесно мащабиране на паралелните задачи, като скрива сложността на управлението на нишките на ОС от разработчика.

// Пример за създаване на goroutine
func myFunc() {
	// Код на goroutine
}

func main() {
	go myFunc() // Стартиране на goroutine
	// Основната програма продължава изпълнението си паралелно
}