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 的内存。

相关推荐
Slow菜鸟6 小时前
AI学习篇(三) | AI效率工具指南(2026年)
人工智能·学习
qcwl666 小时前
深入理解Linux进程与内存 学习笔记#4
笔记·学习
蒸蒸yyyyzwd7 小时前
后端学习笔记 day4
linux·笔记·学习
笨笨饿9 小时前
20_Git 仓库使用手册 - 初学者指南
c语言·开发语言·嵌入式硬件·mcu·学习
人间打气筒(Ada)9 小时前
go实战案例:如何通过 Service Meh 实现熔断和限流
java·开发语言·golang·web·istio·service mesh·熔断限流
cqbelt9 小时前
Python 并发编程实战学习笔记
笔记·python·学习
智算菩萨10 小时前
【论文复现】Applied Intelligence 2025:Auto-PU正例无标签学习的自动化实现与GPT-5.4辅助编程实战
论文阅读·python·gpt·学习·自动化·复现
老神在在00110 小时前
【Selenium 自动化精讲】浏览器弹窗与登录界面的本质区别 & 实操指南
javascript·学习·selenium·测试工具·自动化
weixin_4491904110 小时前
defer和defer func执行区别
golang
·醉挽清风·11 小时前
学习笔记—Linux—信号阻塞&信号捕捉
linux·笔记·学习