Advertisement
Guest User

Untitled

a guest
Jan 15th, 2020
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 5.94 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "time"
  5.     "context"
  6.     "fmt"
  7.     "math/rand"
  8. )
  9.  
  10. // Медленная функция
  11. func sleepRandom(fromFunction string, ch chan int) {
  12.     // Отложенная функция очистки
  13.     defer func() { fmt.Println(fromFunction, "sleepRandom complete") }()
  14.  
  15.     // Выполним медленную задачу
  16.     // В качестве примера,
  17.     // «заснем» на рандомное время в мс
  18.     seed := time.Now().UnixNano()
  19.     r := rand.New(rand.NewSource(seed))
  20.     randomNumber := r.Intn(100)
  21.     sleeptime := randomNumber + 100
  22.  
  23.     fmt.Println(fromFunction, "Starting sleep for", sleeptime, "ms")
  24.     time.Sleep(time.Duration(sleeptime) * time.Millisecond)
  25.     fmt.Println(fromFunction, "Waking up, slept for ", sleeptime, "ms")
  26.  
  27.     // Напишем в канал, если он был передан
  28.     if ch != nil {
  29.         ch <- sleeptime
  30.     }
  31. }
  32.  
  33. // Функция, выполняющая медленную работу с использованием контекста
  34. // Заметьте, что контекст - это первый аргумент
  35. func sleepRandomContext(ctx context.Context, ch chan bool) {
  36.  
  37.     // Выполнение (прим. пер.: отложенное выполнение) действий по очистке
  38.     // Созданных контекстов больше нет
  39.     // Следовательно, отмена не требуется
  40.     defer func() {
  41.         fmt.Println("sleepRandomContext complete")
  42.         ch <- true
  43.     }()
  44.  
  45.     // Создаем канал
  46.     sleeptimeChan := make(chan int)
  47.  
  48.     // Запускаем выполнение медленной задачи в горутине
  49.     // Передаем канал для коммуникаций
  50.     go sleepRandom("sleepRandomContext", sleeptimeChan)
  51.  
  52.     // Используем select для выхода по истечении времени жизни контекста
  53.     select {
  54.     case <-ctx.Done():
  55.         // Если контекст отменен, выбирается этот случай
  56.         // Это случается, если заканчивается таймаут doWorkContext или
  57.         // doWorkContext или main вызывает cancelFunction
  58.         // Высвобождаем ресурсы, которые больше не нужны из-за прерывания работы
  59.         // Посылаем сигнал всем горутинам, которые должны завершиться (используя каналы)
  60.         // Обычно вы посылаете что-нибудь в канал,
  61.         // ждете выхода из горутины, затем возвращаетесь
  62.         // Или используете группы ожидания вместо каналов для синхронизации
  63.         fmt.Println("sleepRandomContext: Time to return")
  64.  
  65.     case sleeptime := <-sleeptimeChan:
  66.         // Этот вариант выбирается, когда работа завершается до отмены контекста
  67.         fmt.Println("Slept for ", sleeptime, "ms")
  68.     }
  69. }
  70.  
  71. // Вспомогательная функция, которая в реальности может использоваться для разных целей
  72. // Здесь она просто вызывает одну функцию
  73. // В данном случае, она могла бы быть в main
  74. func doWorkContext(ctx context.Context) {
  75.  
  76.     // От контекста с функцией отмены создаём производный контекст с тайм-аутом
  77.     // Таймаут 150 мс
  78.     // Все контексты, производные от этого, завершатся через 150 мс
  79.     ctxWithTimeout, cancelFunction := context.WithTimeout(ctx, time.Duration(150)*time.Millisecond)
  80.  
  81.     // Функция отмены для освобождения ресурсов после завершения функции
  82.     defer func() {
  83.         fmt.Println("doWorkContext complete")
  84.         cancelFunction()
  85.     }()
  86.  
  87.     // Создаем канал и вызываем функцию контекста
  88.     // Можно также использовать группы ожидания для этого конкретного случая,
  89.     // поскольку мы не используем возвращаемое значение, отправленное в канал
  90.     ch := make(chan bool)
  91.     go sleepRandomContext(ctxWithTimeout, ch)
  92.  
  93.     // Используем select для выхода при истечении контекста
  94.     select {
  95.     case <-ctx.Done():
  96.         // Этот случай выбирается, когда переданный в качестве аргумента контекст уведомляет о завершении работы
  97.         // В данном примере это произойдёт, когда в main будет вызвана cancelFunction
  98.         fmt.Println("doWorkContext: Time to return")
  99.  
  100.     case <-ch:
  101.         // Этот вариант выбирается, когда работа завершается до отмены контекста
  102.         fmt.Println("sleepRandomContext returned")
  103.     }
  104. }
  105.  
  106. func main() {
  107.     // Создаем контекст background
  108.     ctx := context.Background()
  109.     // Производим контекст с отменой
  110.     ctxWithCancel, cancelFunction := context.WithCancel(ctx)
  111.  
  112.     // Отложенная отмена высвобождает все ресурсы
  113.     // для этого и производных от него контекстов
  114.     defer func() {
  115.         fmt.Println("Main Defer: canceling context")
  116.         cancelFunction()
  117.     }()
  118.  
  119.     // Отмена контекста после случайного тайм-аута
  120.     // Если это происходит, все производные от него контексты должны завершиться
  121.     go func() {
  122.         sleepRandom("Main", nil)
  123.         cancelFunction()
  124.         fmt.Println("Main Sleep complete. canceling context")
  125.     }()
  126.  
  127.     // Выполнение работы
  128.     doWorkContext(ctxWithCancel)
  129. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement