Sobes.tech
Junior

Какво е контекст в Go?

sobes.tech AI

Отговор от AI

Контекстът (context.Context) в Go е обект, който носи срок за изпълнение, сигнал за отменяне (cancellation signal) и данни, специфични за заявката. Използва се за управление на жизнения цикъл на горутините и пренасяне на информация между тях по време на изпълнение на една заявка/операция.

Основни характеристики:

  • Безопасен за нишки: Може безопасно да се пренася между горутините.
  • Иммутабилен: След създаване, Context не може да бъде променян. Производните контексти се създават въз основа на родителския.
  • Иерархичен: Контекстите образуват дърво с корен (context.Background() или context.TODO()). Отмяната на родителския контекст води до отмяна на всички дъщерни.

Основни функции на пакета context:

  • context.Background(): Празен контекст, обикновено се използва в главната функция, при горни заявки или при тестове. Никога не е отменен.
  • context.TODO(): Също празен контекст. Използва се като заместител, когато не е известно кой контекст да се използва, или ако функционалността на контекста все още не е реализирана.
  • context.WithCancel(parent Context): Връща нов дъщерен контекст и функция за отмяна. Викайки функцията за отмяна, този контекст и всички негови дъщерни се отменят.
  • context.WithDeadline(parent Context, deadline time.Time): Връща дъщерен контекст, който автоматично се отменя, когато настъпи посоченото време. Връща също така функция за ръчно отмяна.
  • context.WithTimeout(parent Context, timeout time.Duration): Същото като WithDeadline, но с указание за продължителност.
  • context.WithValue(parent Context, key, val interface{}): Връща дъщерен контекст с присвоена стойност по ключ.

Приложение:

  • Отмяна на операции: Например, таймаут на HTTP заявка или прекъсване на дълга операция.
  • Пренасяне на данни: Например, ID на заявката за логиране, автентификационна информация.

Пример за използване на context.WithTimeout:

package main

import (
	"context"
	"fmt"
	"time"
)

func longRunningOperation(ctx context.Context, resultChan chan string) {
	select {
	case <-time.After(3 * time.Second):
		// Операцията е успешно завършена
		resultChan <- "Operation completed"
	case <-ctx.Done():
		// Контекстът е отменен
		err := ctx.Err() // Получаване на причината за отмяна
		resultChan <- fmt.Sprintf("Operation cancelled: %v", err)
	}
}

func main() {
	// Създаване на контекст с таймаут 2 секунди
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // Гарантирано извикване на функцията за отмяна

	resultChan := make(chan string, 1)

	go longRunningOperation(ctx, resultChan)

	// Изчакване за резултат или отмяна
	select {
	case res := <-resultChan:
		fmt.Println(res)
	case <-ctx.Done():
		fmt.Printf("Main context done: %v\n", ctx.Err())
	}

	// Малко изчакване, за да може горутината да приключи, ако е била отменена
	time.Sleep(1 * time.Second)
}

В този пример longRunningOperation проверява за отмяна на контекста. Ако таймаутът на основния контекст (2 секунди) изтече преди да приключи операцията (3 секунди), горутината получава сигнал за отмяна чрез ctx.Done() и приключва.