Context, propagation и cancellation patterns в Go vs Java | Паттерны, идиомы и лучшие практики Go

1. Context и его роль

В Go context.Context используется для передачи сигналов отмены и таймаутов между goroutine, а также для передачи значений (propagation). Для Java-разработчиков это частично похоже на Future с отменой, Thread.interrupt() и ThreadLocal.


// Go: базовый контекст с таймаутом
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

go func(ctx context.Context) {
    select {
    case <-time.After(5 * time.Second):
        fmt.Println("Горрутина завершена")
    case <-ctx.Done():
        fmt.Println("Горрутина отменена:", ctx.Err())
    }
}(ctx)

// Java: отмена через Future и ExecutorService
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> f = executor.submit(() -> {
    try {
        Thread.sleep(5000);
        System.out.println("Задача завершена");
    } catch (InterruptedException e) {
        System.out.println("Задача отменена");
    }
});
f.cancel(true); // отмена
executor.shutdown();
Context помогает передавать сигналы отмены и таймауты между goroutine, что особенно важно в параллельных и сетевых задачах.

2. Context propagation

Значения можно передавать через контекст, чтобы все дочерние goroutine получали общую информацию без глобальных переменных.


// Go: передача значения через контекст
ctx := context.WithValue(context.Background(), "userID", 42)

go func(ctx context.Context) {
    fmt.Println("UserID:", ctx.Value("userID"))
}(ctx)

// Java: ThreadLocal для передачи контекста
ThreadLocal<Integer> userID = ThreadLocal.withInitial(() -> 42);

Runnable task = () -> System.out.println("UserID: " + userID.get());
new Thread(task).start();
В Go context propagation упрощает передачу данных и сигналов отмены через иерархию goroutine, вместо глобальных переменных или сложных передач параметров.

3. Cancellation patterns

Контекст позволяет гибко отменять задачи. Основные подходы:

  • timeout / deadline
  • явная отмена через cancel()
  • комбинация с select для неблокирующего ожидания

// Go: комбинированный пример fan-in с отменой
func worker(ctx context.Context, jobs <-chan int, results chan<- int) {
    for {
        select {
        case j, ok := <-jobs:
            if !ok { return }
            results <- j * 2
        case <-ctx.Done():
            return
        }
    }
}

ctx, cancel := context.WithCancel(context.Background())
jobs := make(chan int)
results := make(chan int)
go worker(ctx, jobs, results)

// Отмена
cancel()
Используйте context для безопасной отмены всех связанных goroutine, особенно в fan-in/fan-out схемах.

4. Таблица сравнения Go vs Java

Концепт Go Java Комментарий
Отмена задачи context с cancel(), таймаутами и deadline Future.cancel(), Thread.interrupt() Go позволяет безопасно и централизованно отменять все дочерние goroutine
Передача данных context.WithValue() передает значения по иерархии goroutine ThreadLocal или параметры метода В Go меньше глобальных переменных, безопасно в параллельных задачах
Fan-in / Fan-out goroutine + channels + select + context для отмены ExecutorService + BlockingQueue + Future + ручная отмена Go делает паттерн более лёгким и управляемым
Таймауты context.WithTimeout / WithDeadline Future.get(timeout), ScheduledExecutor Контекст обеспечивает единый способ задания таймаутов для всей цепочки goroutine

Итог

Использование context.Context — ключ к безопасной и управляемой параллельности в Go. Он объединяет три задачи:

  • Передача данных между goroutine (propagation)
  • Отмена задач (cancellation)
  • Таймауты и deadlines

Для Java-разработчиков контекст аналогичен комбинации ThreadLocal + Future/interrupt + timeout. Go даёт более прямой, единый и безопасный механизм управления, особенно в схемах fan-in/fan-out.


🌐 in English
Всего лайков:0

Оставить комментарий

Мой канал в социальных сетях
Отправляя email, вы принимаете условия политики конфиденциальности

Полезные статьи:

От микросервисной революции к эпохе эффективности
Период 2010–2020 годов можно назвать эпохой разделения и масштабирования. Системы стали слишком большими, чтобы оставаться монолитами. Решением стали микросервисы — маленькие автономные приложения, ра...
Условные операторы в Java
Java — Условные операторы Наглядная статья с примерами: if / else / логика / тернарный оператор / switch Кратко — условные операторы позволяют программе принимать решения: выполнить один кусок кода ...
Разбираем: Rate‑limiter, non‑blocking operations, scheduler  Go vs Java | Concurrency часть 4
Эта статья посвящена пониманию принципов работы с конкурентностью и синхронизацией в Go и Java. Мы рассмотрим ключевые подходы, такие как rate‑limiter, неблокирующие операции и планирование задач, сра...

Новые статьи:

Конкурентность — это не про «запустить много потоков». Это про договорённости между ними. Представь кухню ресторана: — повара (потоки / горутины) — заказы (задачи) — и главный вопрос: как они коорди...
История начинается не с академической теории, а с типичной production-проблемы. Представьте сервис: 48 CPU 300+ потоков нагрузка 200k операций в секунду много shared state Команда использует обы...
Когда HashMap начинает убивать продакшн: инженерная история ConcurrentHashMap
Представьте обычный продакшн-сервис. 32 CPU сотни потоков кэш конфигурации / сессий / rate limits десятки тысяч операций в секунду И где-то внутри — обычный Map. Сначала всё выглядит безобидно. Map&...
Fullscreen image