Golang学习之time包与net/http 包

go 复制代码
package main

import (
	"context"
	"fmt"
	"net/http"
	"time"
)

// --- 1. time 包深度解析 ---

func timeDeepDive() {
	fmt.Println("=== 1. time 包:除了计时,还能控制节奏 ===")

	// A. 定时器 (Timer):只响一次的闹钟
	timer := time.NewTimer(2 * time.Second)
	fmt.Println("定时器已启动,等待 2 秒...")
	<-timer.C // 阻塞,直到时间到
	fmt.Println("闹钟响了!")

	// B. 打点器 (Ticker):有节奏的脉搏
	fmt.Println("\n打点器演示:每 500ms 跳动一次,跳动 3 次结束")
	ticker := time.NewTicker(500 * time.Millisecond)
	count := 0
	for t := range ticker.C {
		fmt.Printf("Tick at %v\n", t.Format("15:04:05.000"))
		count++
		if count >= 3 {
			ticker.Stop() // 必须手动停止,否则会持续占用内存
			break
		}
	}

	// C. 超时控制 (Timeout): select 的经典用法
	fmt.Println("\n超时控制:模拟一个耗时 3s 的任务,但我们只给 1s")
	eventCh := make(chan string)
	go func() {
		time.Sleep(3 * time.Second)
		eventCh <- "任务完成"
	}()

	select {
	case res := <-eventCh:
		fmt.Println("收到结果:", res)
	case <-time.After(1 * time.Second): // 核心:这就是"超时炸弹"
		fmt.Println("⚠️ 超时了!我不等了。")
	}
}

// --- 2. net/http 包深度解析 ---

func httpDeepDive() {
	fmt.Println("\n=== 2. net/http 包:工业级 HTTP 栈 ===")

	// A. 深度定制 Client:不要直接用 http.Get
	// 在生产环境中,这是必须的,用来控制资源
	client := &http.Client{
		Timeout: 5 * time.Second, // 整个请求(含握手、读数据)的总超时
		Transport: &http.Transport{
			MaxIdleConns:        10,
			IdleConnTimeout:     30 * time.Second,
			DisableCompression: true,
		},
	}

	// B. 使用 Context 控制请求
	// 这在大型微服务中非常重要,父级取消,子级全断
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	req, _ := http.NewRequestWithContext(ctx, "GET", "https://go.dev", nil)
	
	fmt.Println("发起带 Context 的 HTTP 请求...")
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("请求失败(可能是超时): %v\n", err)
		return
	}
	defer resp.Body.Close()

	// C. 流式读取 (Streaming)
	// Body 是一个流,不是内存中的字符串。读多少,占多少内存
	fmt.Printf("状态码: %d\n", resp.StatusCode)
	
	// 读取前 100 字节看看
	buffer := make([]byte, 100)
	n, _ := resp.Body.Read(buffer)
	fmt.Printf("响应前 %d 字节内容: %s...\n", n, string(buffer[:n]))
}

func main() {
	timeDeepDive()
	httpDeepDive()
}

1. time 包:不仅看表,更能"控制节奏"

lib_deep_dive.go 里的 timeDeepDive() 函数看到这三种用法:

A. time.NewTimer (定时器)

就像一个"只响一次的闹钟"。设置好时间后,程序会通过 <-timer.C 在那里死等着,直到时间到了才往下走。这就像你煮泡面设定的 3 分钟倒计时。

B. time.NewTicker (打点器)

一旦开启,它就会跳动,每隔设定的时间,就往通道里塞一个信号。

实战场景:我们可以用它来做后台任务,规定"每隔 5 秒钟去数据库检查一次有没有新订单"。

注意:用完一定要 ticker.Stop(),否则节拍器会一直跳,造成内存泄漏。

C. time.After (超时炸弹) 🌟

最常用,我们在代码里模拟了一个耗时 3 秒的任务,但通过 select 和 time.After(1 * time.Second) 设下了一个陷阱。 谁先完成,就执行谁的代码块。完美解决了"如果你不理我,我也不能干等你一辈子"的问题。

2. net/http 包:工业级的网络栈

在 httpDeepDive() 函数里,我展示了真正在公司里写底层代码的姿势:

A. 深度定制 http.Client

绝对不要在生产环境直接用简单的 http.Get。我们创建了一个定制的 Client,里面规定了:

总超时 (Timeout):如果 5 秒还没处理完,直接砍掉。

连接池 (Transport):它能维持与目标服务器的长连接,而不是每次请求都重新握手,极大地提升了并发性能。

B. Context 的运用 Context(上下文)

是 Go 语言非常强大的一个包,通常和网路请求绑在一起。它就像一根"风筝线",当你发出一个复杂的请求(比如这个请求还要去调其他三个数据库),一旦前端用户点了一下"取消",或者触发了 Context 设置的超时,这根线一断,所有的下游请求会瞬间全部被撤回。

C. 流式读取响应 (resp.Body.Read)

在咱们之前的下载器里,我用 io.Copy 一次性抽干了数据。如果我要下一个 10GB 的文件怎么办? 答案就是"每次用一个小勺子(比如 100 字节的 buffer)舀水"。这样无论文件多大,你的程序永远只占几十 KB 的内存。

相关推荐
小陈phd2 小时前
多模态大模型学习笔记(十一)——transformer学习之绪论
笔记·学习·transformer
做怪小疯子2 小时前
AI大模型RAG与Agent开发学习
人工智能·学习
周淳APP2 小时前
【HTTP之跨域请求以及Cookie携带的限制】
前端·网络·网络协议·http
liliangcsdn2 小时前
LLM任务拆分方法的学习和探索
学习
lars_lhuan2 小时前
Go 方法
开发语言·后端·golang
星幻元宇VR2 小时前
VR社区安全学习机|开启智慧社区新模式
科技·学习·安全·vr·虚拟现实
星幻元宇VR2 小时前
智慧反诈新时代|VR反诈骗学习机的应用解析
科技·学习·vr·虚拟现实
J.Kuchiki2 小时前
【PostgreSQL内核学习:修复 WindowAgg Run Condition 判断逻辑错误的优化】
数据库·学习·postgresql
周淳APP2 小时前
【HTTP相关及RESTful】风萧萧兮易水寒之壮士学习不复返
前端·javascript·网络·网络协议·http·restful·jsonp