|
|
@@ -1,8 +1,8 @@
|
|
|
-# Лекция 1. Контексты
|
|
|
+# Занятие 1. Контексты
|
|
|
|
|
|
## Оглавление
|
|
|
|
|
|
-- [Лекция 1. Контексты](#лекция-1-контексты)
|
|
|
+- [Занятие 1. Контексты](#занятие-1-контексты)
|
|
|
- [Оглавление](#оглавление)
|
|
|
- [Что это такое](#что-это-такое)
|
|
|
- [Зачем нужно](#зачем-нужно)
|
|
|
@@ -37,23 +37,36 @@ ctxBg := context.Background()
|
|
|
|
|
|
### Дочерний контекст с простой отменой
|
|
|
|
|
|
-Дочерний контекст с простой отменой:
|
|
|
+Дочерний контекст с простой отменой. Он используется тогда ,когда время выполнения операции *не важно*.
|
|
|
+
|
|
|
+Пример:
|
|
|
|
|
|
```go
|
|
|
+// FindRecord -- найти запись по её имени
|
|
|
func FindRecord(ctxApp app.AppContext, numRecord string) error {
|
|
|
+ // Дочерний контекст с простой отменой
|
|
|
ctxWork, fnCancel := context.WithCancel(ctxApp)
|
|
|
+ // Обязательно отменить контекст при выходе, иначе будет утечка памяти
|
|
|
defer fnCancel()
|
|
|
+
|
|
|
+ // Канал, который по факту ничего не передаёт.
|
|
|
+ // Но его закрытие будет сигналом об окончании работы конкурентного потока
|
|
|
chWork := make(chan int, 2)
|
|
|
+
|
|
|
+ // Функция-обработчик. Должна работать конкурентно.
|
|
|
fnRead :=func(){
|
|
|
+ // Обязательно закрыть канал при выходе. Это:
|
|
|
+ // 1) Сигнал об окончании работы в любом случае
|
|
|
+ // 2) Если канал не закрыть -- будет утечка памяти
|
|
|
defer close(chWork)
|
|
|
err:=file.FindRecord(numRecord)
|
|
|
if err!=nil{
|
|
|
ctxApp.Cancel()
|
|
|
}
|
|
|
}
|
|
|
- go fnRead()
|
|
|
- select {
|
|
|
- case <-ctxApp.Done(): // Отмена контекста приложения
|
|
|
+ go fnRead() // Запустить конкурентно
|
|
|
+ select { // Устроить соревнование между контекстом и выполняемым запросом
|
|
|
+ case <-ctxApp.Done(): // Отмена контекста приложения, всё остальное уже не интересно
|
|
|
return fmt.Errorf("FindRecord(): cancel ctxApp")
|
|
|
// Ожидание окончания работы, всё-равно
|
|
|
// когда-нибудь закончится так или иначе.
|
|
|
@@ -113,12 +126,12 @@ func Index(ctx context.Context, request *IndexRequest) (*IndexResponse, error) {
|
|
|
}
|
|
|
chResp <- resp
|
|
|
return
|
|
|
+ }
|
|
|
+ resp := &Resp { // Ошибки не было -- значит вернём только результат.
|
|
|
+ err: err,
|
|
|
+ }
|
|
|
+ chResp <- resp
|
|
|
}
|
|
|
- resp := &Resp { // Ошибки не было -- значит вернём только результат.
|
|
|
- err: err,
|
|
|
- }
|
|
|
- chResp <- resp
|
|
|
- }
|
|
|
|
|
|
go fnWork() // Обязательно! Запуск в отдельном потоке
|
|
|
|
|
|
@@ -126,7 +139,7 @@ func Index(ctx context.Context, request *IndexRequest) (*IndexResponse, error) {
|
|
|
case <-ctxTimeout.Done(): // Был ли таймаут дочернего контекста?
|
|
|
return nil, fmt.Errorf("Index(): timeout in make response")
|
|
|
case result := <-chResp: // Что там с результатом?
|
|
|
- if result.err != nil {
|
|
|
+ if result.err != nil { // Увы. но была ошибка
|
|
|
return nil, fmt.Errorf("Index(): in make response, err=\n\t%w", result.err)
|
|
|
}
|
|
|
// Всё ок, возвращаем полезный результат
|