go语言的net/http包的基础使用

该博客详细介绍了在Go语言中如何实现HTTP GET请求,并探讨了不同groutine退出策略,包括使用全局变量、通道以及官方推荐的context包。示例代码展示了如何在groutine中优雅地停止执行,特别是在有超时限制的情况下。同时,还展示了如何在groutine中传递和使用上下文值来控制执行流程。

写一个能发声get请求的http协议的client端

func main() {
	resp, err := http.Get("http://www.baidu.com") //使用get方法请求百度主页的内容.
	if err != nil {
		fmt.Printf("get failed ,err :%v\n", err)
		return
	}
	defer resp.Body.Close() //注意这里使用defer关闭的是resp.body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("read from resp.Body failed,err :%v\n", err)
		return
	}
	fmt.Print(string(body)) //这里要将body内容转换成字符串形式进行显示.
}

返回结果
网页返回的结果.

带参数的get请求实例

var wg sync.WaitGroup

func worker() {
	for {
		fmt.Println("worker")
		time.Sleep(time.Second)
		
	}
wg.Done() //这里是无法退出的.因为进入到worker函数中后执行for循环,循环没又退出的条件.

}

func main() {
	wg.Add(1)
	go worker()
	wg.Wait()
	fmt.Println("over")

}

使用全局变量让grouting退出

//全局变量方式
var wg sync.WaitGroup
var exit bool

func worker() {
	for {
		fmt.Println("worker")
		time.Sleep(time.Second)
		if exit {
			break
		}
	}
	wg.Done()
}

func main() {
	wg.Add(1)
	go worker()
	time.Sleep(time.Second * 3)
	exit = true
	wg.Wait()
	fmt.Println("over")
}
输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
worker
worker
worker
over

使用通道方式退出

//通道方式退出
var wg sync.WaitGroup

func worker(exitChan chan bool) {
LOOP:
	for {
		fmt.Println("sorker")
		time.Sleep(time.Second)
		select {
		case <-exitChan:
			break LOOP
		default:

		}

	}
	wg.Done()
}

func main() {
	var exitChan = make(chan bool)
	wg.Add(1)
	go worker(exitChan)
	time.Sleep(time.Second * 3)
	exitChan <- true
	close(exitChan)
	wg.Wait()
	fmt.Println("over")
}
输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
sorker
sorker
sorker
over

说明一下.这里使用的是channel方式进行退出操作.
将groutine中预先设置传参类型为channel类型,==>在main中将制定的值传入到channel中,==>channel中的数据在groutine中就成了一个触发点.只要满足channel的触发条件就可以退出groutine.

使用官方推荐的版本退出groutine

//官方版本退出groutine

var wg sync.WaitGroup

func worker1(ctx context.Context) {
LOOP:
	for {
		fmt.Println("worker1")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done(): //将触发结束标志.结束当前循环.跳出LOOP循环体.
			break LOOP
		default:

		}
	}
	wg.Done() //减少计数.为主函数中的
}

func worker2(ctx context.Context) {
LOOP:
	for {
		fmt.Println("worker2")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done():
			break LOOP
		default:

		}
	}
	wg.Done()
}

func main() {
	ctx, cancel := context.WithCancel(context.Background()) //声明ctx参数+方法,和cancel结束标志,在后面的groutine的时候调用.
	wg.Add(2)
	go worker1(ctx)
	go worker2(ctx)
	time.Sleep(time.Second * 3)
	cancel()  //一个结束信号,向goroutine中专递一个参数.让groutine出发结束标志.
	wg.Wait() //统计groutine数量全部结束.并向下执行其他语句.(如果没有的话也可以向下执行其他语句,但是不能保证groutine全部关闭.
	fmt.Println("over")
}

输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
worker1
worker2
worker2
worker1
worker1
worker2
worker1
worker2
over

 

func gen(ctx context.Context) chan int {
	dst := make(chan int)
	n := 1
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case dst <- n:
				n++
			default:

			}
		}
	}()
	return dst
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() //结束goroutine

	for n := range gen(ctx) {
		fmt.Println(n)
		if n == 5 {
			break
		}
	}
}

输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
1
2
3
4
5

上面的示例代码中,gen函数在单独的goroutine中生成整数并将它们发送到返回的通道。 gen的调用者在使用生成的整数之后需要取消上下文,以免gen启动的内部goroutine发生泄漏。

 使用预设值的超时时间进行groutine的退出

var wg sync.WaitGroup

func worker(ctx context.Context) {
LOOP:
	for {
		select {
		case <-ctx.Done(): //50毫秒后自动调用.
			break LOOP
		default:  //将默认的操作放到default中进行操作更容易理解一些.
			fmt.Println("db connecting ...")
			time.Sleep(time.Millisecond * 10) //假设正常连接数据库耗时10毫秒
		}
	}
	fmt.Println("worker done")
	wg.Done()
}

func main() {
	//设置一个50毫秒的超时时间,一单时间到了就会自动调用groutine中的ctx.done()用来结束groutine
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	wg.Add(1)
	go worker(ctx)
	time.Sleep(time.Second * 5)
	cancel() //通知子groutine结束
	wg.Wait()
	fmt.Println("Over")
}

输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
db connecting ...
db connecting ...
db connecting ...
db connecting ...
db connecting ...
worker done
Over

waitValue

type TranceCode string

var wg sync.WaitGroup

func worker(ctx context.Context) {
	key := TranceCode("Trance_CODE")
	tranceCode, ok := ctx.Value(key).(string) //在groutine中获取trace code
	if !ok {
		fmt.Println("invalid trace code")
	}
LOOP:
	for {

		select {
		case <-ctx.Done():
			break LOOP
		default:
			fmt.Printf("worker,trace code %s\n", tranceCode)
			time.Sleep(time.Millisecond * 10)
		}
	}
	fmt.Println("worker done!")
	wg.Done()
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) //这里传入的貌似是一个时间段用来设定超时时间.
	// 到了时间之后就将一个结束参数传入到goroutine中.
	ctx = context.WithValue(ctx, TranceCode("Trace_CODE"), "123445324234")
	wg.Add(1)
	go worker(ctx)
	time.Sleep(time.Second * 5)
	cancel()
	wg.Wait()
	fmt.Println("over")
}
输出结果
D:\Go\Go\src\code.oldboy.com\studygolang\05lesson5\fuwud>fuwud.exe
invalid trace code
worker,trace code
worker,trace code
worker,trace code
worker,trace code
worker,trace code
worker done!
over

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值