Quando a corrotina pai introduzida no go 1.7 deseja fechar a corrotina filha, é chamada a função de cancelamento do seu contexto, que enviará um sinal ao seu canal.
A função do Contexto pode ser refletida em dois aspectos: enviar sinais de terminação para métodos; passar alguns dados comuns para múltiplos métodos.
As quatro principais estruturas de Contexto, o uso de CancelContext, TimeoutContext, DeadLineContext e ValueContext
Quais são os cenários aplicáveis?
Por algum motivo (tempo limite ou saída forçada) queremos abortar a tarefa de cálculo desta goroutine, então podemos usar este Contexto
Componentes comuns de controle de simultaneidade: waitGroup, Context
Cenários de uso específicos:
1. Uso de Rpc, solicitação http. Agrupados em uma categoria estão os tempos limite usando withCancel. cancel() será chamado várias vezes e a chamada de cancelamento no pacote de contexto é idempotente. Você pode chamá-lo várias vezes com confiança. Controle paralelo assíncrono, se uma determinada chamada falhar, outras chamadas não serão afetadas
exemplo de código
package main
import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
"time"
)
func main(){
//context控制并发 WithCancel cancel()
ctx,cancel := context.WithCancel(context.Background())
go Worker(ctx,"01")
go Worker(ctx,"02")
go Worker(ctx,"03")
time.Sleep(time.Second * 5)
fmt.Println("stop all")
cancel()
time.Sleep(time.Second * 1)
}
func Worker(ctx context.Context,name string ) {
for {
select{
case <- ctx.Done():
fmt.Println(name," stop the goroutine!")
return
default:
fmt.Println(name," ing")
time.Sleep(time.Second *1)
}
}
}
//结果打印:
//01 ing
//02 ing
//02 ing
//03 ing
//01 ing
//01 ing
//02 ing
//03 ing
//02 ing
//01 ing
//03 ing
//01 ing
//02 ing
//03 ing
//stop all
//02 stop the goroutine!
//03 stop the goroutine!
//01 stop the goroutine!
context WithCancel cancela o controle e envia um sinal de cancelamento para garantir que todas as goroutines emanadas desta lógica sejam canceladas com sucesso.
2. As solicitações do servidor HTTP transferem dados WithValue entre si. WithContext é frequentemente usado em interceptadores.Após a verificação do cookie, as informações públicas são armazenadas na solicitação e a interface pode recuperá-las sozinha.
exemplo de código
// WithValue 使用
func main(){
ContextWithValue()
}
func ContextWithValue() {
rand.Seed(time.Now().Unix())
ctx := context.WithValue(context.Background(), keyID, rand.Int())
operation1(ctx)
}
func operation1(ctx context.Context) {
fmt.Println("operation1 for id:", ctx.Value(keyID), " completed")
operation2(ctx)
}
func operation2(ctx context.Context) {
fmt.Println("operation2 for id:", ctx.Value(keyID), " completed")
}
3. Solicitação de tempo limite. rpc chama http e chama WithTimeout WithDeadLine (operações demoradas, como arquivo io ou rede io, podem verificar se o tempo restante é suficiente para decidir se deve prosseguir para a próxima etapa)
Os parâmetros de tempo passados em WithDeadLine e withTimeout são diferentes, mas o resto é o mesmo.
Exemplo de código WithTimeout
import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
"time"
)
// WithTimeout
func main(){
// 创建一个空ctx
ctx := context.Background()
// 设置超时时间
cxt, _ := context.WithTimeout(ctx, 1*time.Millisecond)
start := time.Now()
// 创建一个请求 访问谷歌
req, _ := http.NewRequest(http.MethodGet, "http://baidu.com", nil)
// 将带有取消方法的ctx和请求关联
req = req.WithContext(cxt)
client := &http.Client{}
res, err := client.Do(req)
if err!=nil{
fmt.Println("Request failed:", err ," time ",time.Now().Sub(start))
return
}
fmt.Println("Response received, status code:", res.StatusCode)
}
WithTimeout代码示例
func main(){
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second * 4))
defer cancel()
copyFileWithDeadline(ctx)
time.Sleep(time.Second * 5)
}
func copyFileWithDeadline(ctx context.Context) {
deadline, ok := ctx.Deadline()
if ok == false {
return
}
// deadline.Sub(time.Now()) 截止时间与当前时间的差值
isEnough := deadline.Sub(time.Now()) > time.Second * 5
if isEnough {
fmt.Println("copy file")
} else {
fmt.Println("isEnough is false return")
return
}
}
Exemplo de código de simultaneidade controlada por contexto. Observe que a ordem de execução das corrotinas é aleatória. Mas waitgroup é um controle de simultaneidade que pode garantir a execução sequencial.
package main
import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
"time"
)
func main(){
//context控制并发 WithCancel cancel()
ctx,cancel := context.WithCancel(context.Background())
go Worker(ctx,"01")
go Worker(ctx,"02")
go Worker(ctx,"03")
time.Sleep(time.Second * 5)
fmt.Println("stop all")
cancel()
time.Sleep(time.Second * 1)
}
func Worker(ctx context.Context,name string ) {
for {
select{
case <- ctx.Done():
fmt.Println(name," stop the goroutine!")
return
default:
fmt.Println(name," ing")
time.Sleep(time.Second *1)
}
}
}
//结果打印:
//01 ing
//02 ing
//02 ing
//03 ing
//01 ing
//01 ing
//02 ing
//03 ing
//02 ing
//01 ing
//03 ing
//01 ing
//02 ing
//03 ing
//stop all
//02 stop the goroutine!
//03 stop the goroutine!
//01 stop the goroutine!
func main(){
// waitgroup来控制并发
wg := sync.WaitGroup{}
wg.Add(2)
go func(){
fmt.Println("1 job")
wg.Done()
}()
go func(){
fmt.Println(" 2 job")
wg.Done()
}()
wg.Wait()
fmt.Println(" end")
}
Resumo final:
1. Transferência de valor. --A transferência de valor é apenas uma função auxiliar de contexto, comumente usada: cookies, interceptadores ou informações de log, depuração de registros de informações
2. Controle de tempo limite - tempo limite de configuração http, chamada rpc, - operações demoradas, como arquivo io ou rede io, podem verificar se o tempo restante é suficiente e decidir se devem prosseguir para a próxima etapa.
3. Controle de cancelamento - envie um sinal de cancelamento para garantir que todas as goroutines provenientes de sua própria lógica sejam canceladas com sucesso