欢迎光临
我们一直在努力

Golang学习之time包与net/http 包

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

赞(0)
未经允许不得转载:171主机测评 » Golang学习之time包与net/http 包
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址