golang context

ex1

package main

import (	
	"fmt"
)

// 最佳context 实践
//  Context 目标是实现各个goroutine能及时终止退出。


func main() {
	// Basic ipfsnode setup	
	a := 10
	fmt.Println("hhha")
	fmt.Println(a)	
}

ex2

package main

import "fmt"

// 打印输出, 发送数据到通道
func printHello(ch chan int) {
	fmt.Println("Hello from printHello")
	// 发送一个数据到通道
	ch <- 2
}

func main() {
	/*
	使用make函数,创建一个通道。
	通道是可以带缓冲的, 如果你指定了长度。如ch := make(chan int, 2)

	channel可分为三种类型:
		只读channel:只能读channel里面数据,不可写入
		只写channel:只能写数据,不可读
		一般channel:可读可写
	*/
	ch := make(chan int)
	//内联goroutine. 定义一个函数,直接go调用.
	//结束时,往通道发一个数据作为信号
	go func(){
		fmt.Println("Hello inline")
		//send a value on channel
		ch <- 1
	}()
	//调用一个函数作为 goroutine
	go printHello(ch)
	fmt.Println("Hello from main")

	//首先从通道中取出一个数据, 并赋值给变量,并打印出来
	i := <- ch
	fmt.Println("Recieved ",i)
	//从通道获取第二个数据
	// 如果不需要它, 可以不赋值给变量
	<- ch
}

ex3

/*
context(上下文): 可以理解为timeout(超时), deadline(终止时间线), 或者一个channel(通道)来指示goroutine停止工作并退出
比如,在系统中, 当调用其它网站的接口时,通常速度比较慢, 但是你又依赖它的及时返回, 所以并不打算把这个进行备份请求。 通常会设置一个超时。
*/


/* 结构如下
// deadline终止时间线, cancelation 取消信号, and request-scoped 请求范围值
// 多个goroutines同时使用,是安全的
type Context interface {
    // Done 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知,告诉给context相关的函数要停止当前工作然后返回。
	// 当一个父operation启动一个goroutine用于子operation,这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.
	// Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。
    Done() <-chan struct{}

    // Err方法返回context为什么被取消。
    Err() error

    // Deadline返回context何时会超时。
    Deadline() (deadline time.Time, ok bool)

    // Value返回context相关的数据。
    Value(key interface{}) interface{}
}
*/
// 创建context上下文


// 1. context.Backgrond() ctx Context
// BackGound是所有Context的root,不能够被cancel。
// 这个函数返回一个空的上下文, 这个仅在高层使用(如在main 或者 顶级请求)


/* 2. WithCancel返回一个继承的Context,这个Context在父Context的Done被关闭时关闭自己的Done通道,或者在自己被Cancel的时候关闭自己的Done。
	  WithCancel同时还返回一个取消函数cancel,这个cancel用于取消当前的Context。
*/

package main

import (
	"context"
	"log"
	"os"
	"time"
)

var logg *log.Logger

func someHandler() {
	ctx, cancel := context.WithCancel(context.Background())
	go doStuff(ctx)

	//10秒后取消doStuff
	time.Sleep(10 * time.Second)
	cancel()

}

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
	for {
		time.Sleep(1 * time.Second)
		select {
		case <-ctx.Done():
			logg.Printf("done")
			return
		default:
			logg.Printf("work")
		}
	}
}

func main() {
	logg = log.New(os.Stdout, "", log.Ltime)
	someHandler()
	logg.Printf("down")
}

ex4

/*
context(上下文):
withDeadline withTimeout
*/


/* 结构如下
// deadline终止时间线, cancelation 取消信号, and request-scoped 请求范围值
// 多个goroutines同时使用,是安全的
type Context interface {
    // Done 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知,告诉给context相关的函数要停止当前工作然后返回。
	// 当一个父operation启动一个goroutine用于子operation,这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.
	// Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。
    Done() <-chan struct{}

    // Err方法返回context为什么被取消。
    Err() error

    // Deadline返回context何时会超时。
    Deadline() (deadline time.Time, ok bool)

    // Value返回context相关的数据。
    Value(key interface{}) interface{}
}
*/
package main

import (
	"context"
	"log"
	"os"
	"time"
)

var logg *log.Logger

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
	for {
		time.Sleep(1 * time.Second)
		select {
		case <-ctx.Done():
			logg.Printf("done")
			return
		default:
			logg.Printf("work")
		}
	}
}
func timeoutHandler() {
	// 这里在上下文中加入了超时限制, 超时和取消,取其短。
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))
	go doStuff(ctx)
	time.Sleep(10 * time.Second)
	cancel()
}

func main() {
	logg = log.New(os.Stdout, "", log.Ltime)
	timeoutHandler()
	logg.Printf("end")
}

ex5

/*
context(上下文):
withDeadline withTimeout
*/


/* 结构如下
// deadline终止时间线, cancelation 取消信号, and request-scoped 请求范围值
// 多个goroutines同时使用,是安全的
type Context interface {
    // Done 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知,告诉给context相关的函数要停止当前工作然后返回。
	// 当一个父operation启动一个goroutine用于子operation,这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.
	// Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。
    Done() <-chan struct{}

    // Err方法返回context为什么被取消。
    Err() error

    // Deadline返回context何时会超时。
    Deadline() (deadline time.Time, ok bool)

    // Value返回context相关的数据。
    Value(key interface{}) interface{}
}
*/
package main

import (
	"context"
	"log"
	"os"
	"time"
)

var logg *log.Logger

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
	for {
		time.Sleep(1 * time.Second)
		select {
		case <-ctx.Done():
			logg.Printf("done")
			return
		default:
			logg.Printf("work")
		}
	}
}
func doTimeOutStuff(ctx context.Context) {
	for {
		time.Sleep(1 * time.Second)

		if deadline, ok := ctx.Deadline(); ok { //设置了deadl
			logg.Printf("deadline set")
			if time.Now().After(deadline) {
				logg.Printf(ctx.Err().Error())
				return
			}

		}

		select {
		case <-ctx.Done():
			logg.Printf("done")
			return
		default:
			logg.Printf("work")
		}
	}
}

func timeoutHandler() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	// ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
	go doTimeOutStuff(ctx)
	// go doStuff(ctx)

	time.Sleep(10 * time.Second)

	cancel()

}

func main() {
	logg = log.New(os.Stdout, "", log.Ltime)
	timeoutHandler()
	logg.Printf("end")
}

ex6

/*
context(上下文):
withValue 附加一些(不可变)数据, 供派生goroutine查询用
*/

package main

import (
	"context"
	"log"
	"os"
	"time"
)

const (
	GOLABLE_KEY = "test123"
)

func main() {
	//父context控制子context
	controlAllConrrent()
}

func controlAllConrrent() {

	logg := log.New(os.Stdout, "", log.Ltime)
	handleSome()
	logg.Println("over ")
}

//父协程
func handleSome() {
	//ctx, cancelFunc := context.WithCancel(context.Background())
	//ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2)
	ctx, cancelFunc := context.WithDeadline(context.Background(), time.Now().Add(time.Second*2))

	ctx = context.WithValue(ctx, GOLABLE_KEY, "1234")

	go workerFunc(ctx, "str1")
	go workerFunc(ctx, "str2")
	time.Sleep(time.Second * 3)
	cancelFunc()
}

//子协程
func workerFunc(ctx context.Context, showStr string) {
	for {
		time.Sleep(time.Second * 1)
		select {
		case <-ctx.Done():
			log.Println("done")
			return
		default:
			val123 := ctx.Value(GOLABLE_KEY).(string)
			log.Println(val123, showStr)
		}
	}
}
原文地址:https://www.cnblogs.com/freebird92/p/10518400.html