协程:Goroutine
package main
import (
"fmt"
"sync"
)
type safeInt struct {
a int
lock sync.Mutex
}
//对a 加锁
func (si *safeInt) increase() {
si.lock.Lock()
defer si.lock.Unlock()
si.a++
}
func (si *safeInt) get() int {
si.lock.Lock()
defer si.lock.Unlock()
return si.a
}
func main() {
var si safeInt
si.increase()
//WaitGroup共享内存方式实现并发
var wg sync.WaitGroup
for i := 0; i < 5000; i++ {
wg.Add(1)
go func() {
si.increase()
defer wg.Done()
}()
wg.Wait()
}
fmt.Println(si.get())
}
- 在执行函数前面加上go关键字就表示一个执行一个协程
- 协程是更轻量级的线程,属于非抢占式的线程调度,底层实际还是线程
- main函数也是一个协程
- io操作会交出协程控制权或使用权
channel(常用)
//创建chan的方法
var c chan int // c = nil
c := make(chan int)
- channel是协程与协程之间的一个通道
- 通过make关键字创建channel
- ch <- x 从通道接收数据,x <- ch 从通道中读取数据
- channel可以使用close()函数来关闭
- range channel可以直接取到channel的值
- 通道在前发送数据,通道在后接受数据
- 如果没有 goroutine 读取 channel,则发送者会一直阻塞
buffered channel 和select
package main
import (
"fmt"
"time"
)
func bufferedChannelDemo() {
c := make(chan int, 3)
go func() {
for {
n := <-c
fmt.Println(n)
}
}()
c <- 10
c <- 20
c <- 30
c <- 40
}
func selectDemo() {
ch1 := make(chan int)
ch2 := make(chan int)
timeout := make(chan bool)
go func() {
time.Sleep(time.Second)
timeout <- true
}()
go func() {
ch1 <- 10
}()
//使用select语句和default case来实现非阻塞
for {
select {
case <-ch1:
fmt.Println("receive data from ch1")
case <-ch2:
fmt.Println("receive data from ch2")
case <-timeout:
fmt.Println("timeout")
return
default:
fmt.Println("no data to send channel")
}
}
}
//检测channel是否已满
func checkChannelFull(c chan int) {
select {
case c <- 2:
default:
fmt.Println("channel is full")
}
}
func main() {
//selectDemo()
//bufferedChannelDemo()
//time.Sleep(time.Millisecond)
//<-time.After(time.Millisecond)
c := make(chan int, 3)
c <- 1
c <- 2
checkChannelFull(c)
}
- 带缓冲的通道,可以用make设置缓冲大小
- 在缓冲被全部使用之前,给一个带缓冲的通道发送数据是不会被阻塞的,而从通道读取数据也不会被阻塞,知道缓冲空了为止
- default case可以确保发送不会被阻塞
- 如果阻塞了,会等待直到其中一个可以处理,如果多个可以处理,则随机选择一个处理
http标准库
1、发起request请求:
//自定义http请求添加请求头
func sendRequest() {
req, err := http.NewRequest(http.MethodGet, "http://www.baidu.com", nil)
if err != nil {
panic(err)
}
//添加请求头
req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36")
//发起request请求
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
//获取请求body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
//不添加请求头方式请求
func sendRequest() {
req, err := http.Get("http://www.youdianzhishi.com")
if err != nil {
panic(err)
}
defer req.Body.Close()
data, err := ioutil.ReadAll(req.Body)
if err != nil {
panic(err)
}
fmt.Println(string(data))
}
2、使用http库构建server
//获取文本
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
io.WriteString(writer, "Hello World")
})
//获取json
http.HandleFunc("/json", func(writer http.ResponseWriter, request *http.Request) {
user := User{
Name: "James",
Age: 20,
}
userJson, err := json.Marshal(user)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
writer.Header().Set("Content-Type", "Application/json")
writer.Write(userJson)
})
log.Fatalln(http.ListenAndServe("localhost:8080", nil))
time标准库
func timeDemo() {
//获取当前时间
now := time.Now()
//格式化必须使用"2006-01-02 15:04:05"
now.Format("2006-01-02 15:04:05")
}
rand随机数
func randDemo() {
//返回100之内的随机数。包含100
num := rand.Intn(100)
fmt.Println(num)
}
//init函数最先执行,获取随机数必须先初始化时间戳
func init() {
rand.Seed(time.Now().Unix())
}
json
type BaseResponse struct {
Code int `json:"code"`
Data ResponseData `json:"data"`
}
type ResponseData struct {
Name string `json:"name"`
Age int `json:"age"`
}
func jsonDemo() {
br := BaseResponse{
Code: 200,
Data: ResponseData{
Name: "James",
Age: 20,
},
}
//结构体序列华为json
jsonBytes, _ := json.Marshal(&br)
fmt.Println(string(jsonBytes))
//json反序列化为结构体
var br2 BaseResponse
_ = json.Unmarshal(jsonBytes, &br2)
fmt.Println(br2)
}