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. SSD源码解读——网络搭建

    之前,对SSD的论文进行了解读,可以回顾之前的博客:https://www.cnblogs.com/dengshunge/p/11665929.html. 为了加深对SSD的理解,因此对SSD的源码进 ...

  2. linux库(程序)与包名联系

    一般地,dev为相关开发库包. curses--cursor optimization光标优化--libncurses5-dev 现在常用的是new curses(ncurses). 在ubuntu中 ...

  3. Red Hat Enterprise Linux 6安装好,开启网卡到搭建tftp服务器和安装dnw驱动,安装samba服务器

    今天一顿误操作,只能把Red Hat Enterprise Linux 6重新安装,一些必备工作只能重做,重做之后立马把Linux的文件备份,以备不时只需! 开启Linux以太网卡:vim /etc/ ...

  4. Mac OSX编译安装php7.1.8

    laravel中用到ldap认证包,要求php7.0以上版本,而且安装Mews\Captcha包的时候 验证码无法显示 报错如下: Call to undefined function Interve ...

  5. Dubbo 04 服务化最佳实现流程

    Dubbo 04 服务化最佳实践 分包 建议将服务接口.服务模型.服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原 ...

  6. poj3522 苗条树(极差最小生成树)

    给你N个点和M条边 要求你求出一个生成树使得这个生成树里边权极差最小 做法① n*m做法 当最小的边已知的时候这个生成树就确定 所以最大的边也确定了 于是我们每次枚举最小的边 然后用kruskal做一 ...

  7. Highcharts动态获取值

    <script type="text/javascript">         $(document).ready(function (){         var o ...

  8. constant read 和 current read

    来自网络,并且在本机实验完成: onsistent read :我的理解,就是通过scn来读取.  读取的过程中要保证 scn是一致的.举个例子,一个SELECT 语句在SCN=100的时刻开始读取一 ...

  9. k8spod探测

    一.pod存活性探测 pod spec为容器列表中的相应容器定义其专用的探针即可启用存活性探测,目前,k8s的容器支持存活性探测的方法包含:ExecAction.TCPSocketActon和HTTP ...

  10. 剑指Offer-快速排序

    剑指Offer上的快速排序的Partition函数与我在数据结构书上学到的不一样,因此就想要探索下这两种不同的处理方式. 1.基本思想 快速排序的基本思想是基于分治法.在待排序表L[1...n]中任取 ...