Оглавление:
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.
Галерея
Оставить комментарий
Мой канал в социальных сетях
Полезные статьи:
В этой статье мы разберём внутреннее устройство map / hash-таблиц в Go и Java. Если ты Java-разработчик, привыкший к HashMap, тебе будет интересно, насколько иначе мыслит Go. Если ты гофер — ты увидиш...
Error handling и defer в Go (Параллельность и синхронизация) | Паттерны, идиомы и лучшие практики Go
Обработка ошибок в Go сильно отличается от привычного Java-подхода с исключениями. Вместо try/catch Go использует возврат ошибки как отдельного значения, а `defer` помогает безопасно освобождать ресур...
Серия: Go для Java-разработчиков — разбор trace, профилирования и тестирования В этой статье мы разберем инструменты и практики для тестирования, отладки и профилирования в Go. Для Java-разработчика ...
Новые статьи:
Конкурентность — это не про «запустить много потоков». Это про договорённости между ними. Представь кухню ресторана: — повара (потоки / горутины) — заказы (задачи) — и главный вопрос: как они коорди...
История начинается не с академической теории, а с типичной production-проблемы. Представьте сервис: 48 CPU 300+ потоков нагрузка 200k операций в секунду много shared state Команда использует обы...
Представьте обычный продакшн-сервис. 32 CPU сотни потоков кэш конфигурации / сессий / rate limits десятки тысяч операций в секунду И где-то внутри — обычный Map. Сначала всё выглядит безобидно. Map&...