1.前言

一个请求,可能涉及多个API调用,多个goroutine,如何在多个API 之间,以及多个goroutine之间协作和传递信息,就是一个问题。

比如一个网络请求Request,需要开启一些goroutine去访问后端资源(比如,数据库,RPC服务等),这些goroutine又可能会开启其他的goroutine,如何跟踪和控制这些goroutine呢?

golang定义了 context包,用于解决这个问题。

context可以在多个API和进程之间,实现deadlines截止日期操作、cancelation signals取消操作以及传递request-scoped的值(即传递参数)。

context一个最大的特点是可以继承。父context,可以派生子context,子context有又可以派生子context。如果父context被取消,子context及其子context都会被取消。

常用派生的方法有:WithCancel WithDeadline WithTimeout WithValue.

其中,

  • WithCancel用于主动取消自身以及子context。
  • WithDeadlineWithTimeout用于超时情况下的取消自身以及子context。WithTimeout实现上直接调用WithDeadline
  • WithValue用于context传递request-scoped的参数,而不是向函数传递的可选参数。

2.例子

下面例子演示如何控制多个goroutine的退出。

首先,启动3个goroutine,分别命名为"1"、"2"、"3",每个goroutine又启动一个goroutine。也就是有6个goroutine。它们之间的关系如下:

  • 1

    • 11
  • 2
    • 21
  • 3
    • 31

最后,在main中调用取消操作cancel,先是1,2,3收到信号退出,1,2,3退出的时候又调用它们的cancel,这样所有的goroutine都被取消并退出。

具体代码如下:

package main

import (
"context"
"fmt"
"time"
) func PrintTask(ctx context.Context, taskName string) { for { select { case <- ctx.Done():
fmt.Println("task:", taskName, " exit...")
return
default:
time.Sleep(1*time.Second)
fmt.Println("task:", taskName, " doing something...")
} } } func mainTask(ctx context.Context, taskName string) { ctx1, cancel := context.WithCancel(ctx)
defer cancel() // create a new task
newTaskName := taskName + "1"
go PrintTask(ctx1, newTaskName) for { select { case <- ctx.Done():
fmt.Println("task:", taskName, " exit...")
return
default:
time.Sleep(1*time.Second)
fmt.Println("task:", taskName, " doing something...")
} } } func main() { ctx := context.Background()
ctx, cancel := context.WithCancel(ctx) go mainTask(ctx, "1")
go mainTask(ctx, "2")
go mainTask(ctx, "3") time.Sleep(3*time.Second)
cancel()
fmt.Println("main exit...")
time.Sleep(3*time.Second)
}

输出

task: 1  doing something...
task: 21 doing something...
task: 11 doing something...
task: 3 doing something...
task: 2 doing something...
task: 31 doing something...
task: 3 doing something...
task: 2 doing something...
task: 11 doing something...
task: 21 doing something...
task: 31 doing something...
task: 1 doing something...
task: 11 doing something...
task: 3 doing something...
task: 1 doing something...
task: 21 doing something...
task: 2 doing something...
task: 31 doing something...
main exit...
task: 11 doing something...
task: 11 exit...
task: 21 doing something...
task: 21 exit...
task: 3 doing something...
task: 3 exit...
task: 31 doing something...
task: 31 exit...
task: 1 doing something...
task: 1 exit...
task: 2 doing something...
task: 2 exit...

更多参考

Golang并发控制--context的使用

Golang Context深入理解

golang context学习记录1的更多相关文章

  1. golang context学习记录2

    上篇文章中,我们已经学习了使用context实现控制多个goroutine的退出. 本文将继续介绍如何使用context实现超时情况下,让多个goroutine退出. 例子 首先,启动3个gorout ...

  2. golang "%p"学习记录随笔

    对于获取slice的指针地址, 通过unsafe.Pointer 和 "%p"占位符两种方式得到的地址是不同的 s := make([]int, 1) t.Log(unsafe.P ...

  3. 【golang学习记录】环境搭建

    [golang学习记录]环境搭建 一. 概述 本文是[golang学习记录]系列文章的第一篇,安装Go语言及搭建Go语言开发环境,接下来将详细记录自己学习 go 语言的过程,一方面是为了巩固自己学到的 ...

  4. Golang Context 的原理与实战

    本文让我们一起来学习 golang Context 的使用和标准库中的Context的实现. golang context 包 一开始只是 Google 内部使用的一个 Golang 包,在 Gola ...

  5. Quartz 学习记录1

    原因 公司有一些批量定时任务可能需要在夜间执行,用的是quartz和spring batch两个框架.quartz是个定时任务框架,spring batch是个批处理框架. 虽然我自己的小玩意儿平时不 ...

  6. Spring学习记录(九)---通过工厂方法配置bean

    1. 使用静态工厂方法创建Bean,用到一个工厂类 例子:一个Car类,有brand和price属性. package com.guigu.spring.factory; public class C ...

  7. 【转】BLE 学习记录

    原文网址:http://m.blog.csdn.net/blog/chiooo/43985401 BLE 学习记录 ANROID BLE 开发,基于 bluetoothlegatt 分析 mBluet ...

  8. 我的Spring学习记录(二)

    本篇就简单的说一下Bean的装配和AOP 本篇的项目是在上一篇我的Spring学习记录(一) 中项目的基础上进行开发的 1. 使用setter方法和构造方法装配Bean 1.1 前期准备 使用sett ...

  9. 我的Spring学习记录(四)

    虽然Spring管理这我们的Bean很方便,但是,我们需要使用xml配置大量的Bean信息,告诉Spring我们要干嘛,这还是挺烦的,毕竟当我们的Bean随之增多的话,xml的各种配置会让人很头疼. ...

随机推荐

  1. linux中查看文件夹结构的小工具

    tree命令是Linux/UNIX系统中常用的命令,可以非常方便地查看文件夹的结构,并且以树形目录的形式展示 在Ubuntu中安装 sudo apt-get install tree 在CentOS中 ...

  2. springboot-异步线程调用

    启动类:添加@EnableAsync注解 @SpringBootApplication @EnableAsync public class Application{ public static voi ...

  3. 小米Air安装Arch Linux之图形界面配置(Gnome 和 sway)持续更新中……

    0. 前言 上一篇文章简单讲述了在小米Air上安装Arch Linux的经验,但是安装完后基本系统后,还需要额外的配置才能进到日常使用.下文简单列举一些步骤. 1. 参考网站 主要还是参考ARCH W ...

  4. -bash: ./centos-7.6.sh: /bin/bash^M: bad interpreter问题解决

    在windows下保存了一个脚本文件,用ssh上传到centos,添加权限执行nginx提示没有那个文件或目录.shell脚本放到/etc/init.d/目录下,再执行/etc/init.d/ngin ...

  5. python中的else语句

    python语言和其它语言一样在支持else语句,通常else语句和if语句合用,完成程序的分支选择功能. 例如如下打印学成成绩代码: score = int(input("请输入成绩:&q ...

  6. JavaScript中数组元素删除的七大方法汇总

    原文链接:https://blog.csdn.net/u010323023/article/details/52700770 在JavaScript中,除了Object之外,Array类型恐怕就是最常 ...

  7. vue中前进刷新、后退缓存方案收集

    来源掘金: https://juejin.im/post/5b2ce07ce51d45588a7dbf76 来源博客园 https://www.cnblogs.com/wonyun/p/8763314 ...

  8. grunt-css-sprite css 代码中的切片合并

    安装插件:npm install grunt-css-sprite --save-dev grunt-css-sprite主要功能:1.对 css 文件进行处理,收集切片序列,生成雪碧图2.在原css ...

  9. python中list.sort()与sorted()的区别

    list.sort()和sorted()都是python的内置函数,他们都用来对序列进行排序,区别在于 list.sort()是对列表就地(in-place)排序,返回None:sorted()返回排 ...

  10. 10.17小作业 基于TCP开发一款远程CMD程序

    基于TCP开发一款远程CMD程序 客户端连接服务器后,可以向服务器发送命令 服务器收到命令后执行,无论执行是否成功,无论执行几遍,都将执行结果返回给客户端 注意: 执行系统指令使用subprocess ...