介绍
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
网络程序性能比较差、网络流量高时容易发生并发问题。并发涉及进程、线程的执行,以及CPU对进程、线程的调度等问题,如果没有控制好并发的应对处理,可能造成程序执行错误(如超卖、支付数据错误等严重问题),也会造成网站系统瘫痪等问题。因此并发问题需要对程序的优化、系统调优处理。Go语言自身性能优良、以及提供协程、消息队列等特性,可以有效应对并发问题。
参考
Go语言基础可参看:《Go语言入门及技术指南》 https://blog.youkuaiyun.com/yan_dk/article/details/110557155
《GoLang之网络基本编程》https://blog.youkuaiyun.com/yan_dk/article/details/117621468
示例
示例(协程)
需求:业务程序中存在同时调用redis、mysql、文件处理的逻辑,假设redis需要1秒,mysql需要2秒,文件处理需要3秒,按传统的网络请求处理需要6秒,如何优化?
方案:使用GoLang的协程处理。
程序01/main.go
package main
import (
"fmt"
"time"
)
func redis() {
fmt.Println("start redis")
time.Sleep(time.Second*1)
fmt.Println("redis execting...")
fmt.Println("end redis")
}
func mysql() {
fmt.Println("start mysql")
time.Sleep(time.Second*2)
fmt.Println("mysql execting...")
fmt.Println("end mysql")
}
func file() {
fmt.Println("start file")
time.Sleep(time.Second*3)
fmt.Println("file execting...")
fmt.Println("end file")
}
func main() {
fmt.Println(time.Now())
//time.Sleep(time.Second*6)
go redis()
go mysql()
go file()
time.Sleep(time.Second*3)//主进程设置延时,不然执行过快,看不到线程的输出内容
fmt.Println(time.Now())
}
运行结果
耗时3秒,性能提高一倍。
程序02/main.go(使用线程等待组方式)
package main
import (
"fmt"
"sync"
"time"
)
//使用线程等待组
var wg sync.WaitGroup
func redis() {
defer wg.Done() // 结束登记
fmt.Println("start redis")
time.Sleep(time.Second*1)
fmt.Println("redis execting...")
fmt.Println("end redis")
}
func mysql() {
defer wg.Done() // 结束登记
fmt.Println("start mysql")
time.Sleep(time.Second*2)
fmt.Println("mysql execting...")
fmt.Println("end mysql")
}
func file() {
defer wg.Done() // 结束登记
fmt.Println("start file")
time.Sleep(time.Second*3)
fmt.Println("file execting...")
fmt.Println("end file")
}
func main() {
fmt.Println(time.Now())
//time.Sleep(time.Second*6)
wg.Add(1) // 登记协程
go redis()
wg.Add(1) // 登记协程
go mysql()
wg.Add(1) // 登记协程
go file()
//time.Sleep(time.Second*3)
wg.Wait() // 等待登记的协程执行完再执行后续的程序
fmt.Println(time.Now())
}
运行 结果同上。