Bu örnekte 4 goroutin çalıştırıyoruz ve işlerini bitirmelerini bekliyoruz. Ancak, bunlardan herhangi biri 80 milisaniyeden daha uzun sürerse, bir hata döndüreceğiz. Böyle bir durum ortaya çıkarsa, diğer tüm goroutinler işlerini bitirmelerini beklemeden iptal edilir. Bunun için context.WithCancel özelliğini kullanacağız.


Örnek


package main

import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)

var wg sync.WaitGroup

func main() {
fmt.Println(">>>>> BEGIN")

// Prevent picking up the same random number all the time for sleeping.
rand.Seed(time.Now().UnixNano())

ctx, cancel := context.WithCancel(context.Background())
// Cancel even if everything goes fine without an error to release resources.
defer cancel()

for i := 1; i <= 4; i++ {
wg.Add(1)
go func(i int) {
fmt.Println(i, ": STARTED")
err := doSomething(ctx, &wg, i)
if err != nil {
fmt.Println(err)
cancel()
} else {
fmt.Println(i, ": FINISHED")
}
}(i)
}
wg.Wait()

fmt.Println(">>>>> END")
}

func doSomething(ctx context.Context, wg *sync.WaitGroup, id int) error {
defer wg.Done()

// Pick a random number to simulate time it takes to finish the job.
delay := rand.Intn(100)

select {
case <-ctx.Done():
return fmt.Errorf("%d: CANCELLED (%dms)", id, delay)
default:
// Prevent from blocking.
}

if delay > 80 {
return fmt.Errorf("%d: FAILED (%dms)", id, delay)
}
time.Sleep(time.Duration(delay) * time.Millisecond)

return nil
}

Test


Tümü işlerini 80 milisaniyeden fazla olmayacak şekilde bitirdi.


>>>>> BEGIN
1 : STARTED
2 : STARTED
3 : STARTED
4 : STARTED
2 : FINISHED
4 : FINISHED
3 : FINISHED
1 : FINISHED
>>>>> END

Sadece 1 işini bitirebildi. Her ne kadar 3 ve 4'ün işleri 80 milisaniyeden daha az sürecekdiyse de, her ikiside iptal edildi çünkü 2 daha önceden 84 milisaniyeyle iptal edildi.


>>>>> BEGIN
1 : STARTED
2 : STARTED
2: FAILED (84ms)
3 : STARTED
3: CANCELLED (20ms)
4 : STARTED
4: CANCELLED (14ms)
1 : FINISHED
>>>>> END

1 başlangıçta 99 milisaniyede iptal edildiği için, 80 milisaniyeden daha kısa sürmesi gerekmesine rağmen diğerleride iptal edildi.


>>>>> BEGIN
1 : STARTED
1: FAILED (99ms)
2 : STARTED
2: CANCELLED (73ms)
3 : STARTED
3: CANCELLED (20ms)
4 : STARTED
4: CANCELLED (16ms)
>>>>> END

1 başlangıçta 87 milisaniyede iptal edildiği için diğerleride iptal edildi. Her ne kadar 3 84 milisaniyede iptal olacak şekilde ayarlanmış olsa da, her hangi bir şansı yoktu. O nedenle iptal edildi.


>>>>> BEGIN
1 : STARTED
1: FAILED (87ms)
2 : STARTED
2: CANCELLED (64ms)
3 : STARTED
3: CANCELLED (84ms)
4 : STARTED
4: CANCELLED (77ms)
>>>>> END

3 85 milisaniye ile iptal edildi ama diğerleri işlerini başarıyla bitirdiler. 3 en son sırada başladığı için teknik olarak iptal edilecek hiçbir şey yoktu.


>>>>> BEGIN
1 : STARTED
2 : STARTED
4 : STARTED
3 : STARTED
3: FAILED (85ms)
2 : FINISHED
1 : FINISHED
4 : FINISHED
>>>>> END