go环境变量
$GOPATH
在1.11之前它是我们书写项目的工作目录
在1.11之后它内部存储的是我们公共go.mod下载的依赖包
$GOROOT
安装目录
$GOARCH
目标机器的处理器架构,它的值可以是386、amd64 或arm.
$GoOS
表示目标机器的操作系统,它的值可以是darwin、freebsd、 linux或 windows.
$GOARM
专门针对基于arm架构的处理器,它的值可以是5或6,默认为6。
$GOMAXPROCS
用于设置应用程序可使用的处理器个数与核数
$GOPROXY
配置镜像仓库,下载东西
GO111MODULE
on off auto,包
go并发
有无缓存区
c := make(chan int) # 没有缓存区
c := make(chan int, 5) #有5个缓存区
- 缓存区在存入的时候是会优先把缓存区填满
c := make(chan int, 5)
go func() {
for i := 0; i < 10; i++ {
c <- i
# 2、添加5个值,填满
# 4、空出一个缓存区,存入一个
# 6、又有空出的缓存区 ...
}
}()
for i := 0; i < 10; i++ {
fmt.Println(<-c)
# 1、先运行到这里,等待c中的值,此时c中没有值
# 3、c中有值了,取出第一个0,取出后还有四个
# 5、又满了,取出1,
}
close
当你不需要存入数据的时候使用这个函数关闭
c <- 1
c <- 2
c <- 3
close(c)
c <- 4 # 已经关闭这个=c继续存值会报错
c <- 5
特殊用法
使用for range语法读取channel中的值的时候必须使用close关闭,否则程序报错
c := make(chan int, 5)
c <- 1
c <- 2
c <- 3
c <- 4
c <- 5
close(c) #必须使用close关闭
for v := range c {
fmt.Println(v)
}
select用法
在select中的 case后面的只要是可以执行就会执行,有错误就不会执行‘:‘后面的语句
c1 := make(chan int, 1)
c2 := make(chan int, 1)
c3 := make(chan int, 1)
select {
case <-c1: #这个是有错误的因为c1中没有存值,不是在这里的话会死锁
println("c1")
case <-c2:
println("c2")
case <-c3:
println("c3")
default:
println("都不满足!") # 输出这个
}
后面有多个没有错误就随机执行,即每次执行结果不一样,其实是谁先完成谁就先执行
c1 := make(chan int, 1)
c2 := make(chan int, 1)
c3 := make(chan int, 1)
c1<-1
c2<-1
c3<-1
select {
case <-c1:
println("c1")
case <-c2:
println("c2")
case <-c3:
println("c3")
default:
println("都不满足!")
}
sync包
Mutex和RWMutex
l := &sync.RWMutex{}
go lockFunc(l)
go lockFunc(l)
go readLockFunc(l)
go readLockFunc(l)
go readLockFunc(l)
go readLockFunc(l)
for{}
func lockFunc(lock *sync.RWMutex) {
lock.Lock() // 这个写锁,会排斥其他读锁和写锁,就是在修改这个值的时候其他的协程不能进行读写操作
fmt.Println("执行一次")
time.Sleep(1 * time.Second)
lock.Unlock()
}
func readLockFunc(lock *sync.RWMutex) {
lock.RLock() //读锁不会排斥其他的读锁,但是排斥写锁,就是在读的时候其他的协程也可以读取,但是不能再写(修改值)了
fmt.Println("读取一次")
time.Sleep(1 * time.Second)
lock.RUnlock()
}
Once
只会执行第一个进来的方法,后面的全部锁死
o := &sync.Once{}
for i := 0; i < 10; i++ {
o.Do(func() {
fmt.Println(i)
})
}
输出: 0
永远只会有这一个结果
查看源码:
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 0 {
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
}
func (o *Once) doSlow(f func()) {
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
WaitGroup
类似于原子操作,等Done完之后就会解锁
l := &sync.WaitGroup{}
l.Add(2) // 设置原始值
go func() {
time.Sleep(2 * time.Second)
l.Done() // 原始值减一,
//l.Add(-2) 也可以这样直接减二,这时初始值为0,这个值不能为负数,所以使用done方法安全些
fmt.Println("执行一下")
}()
go func() {
time.Sleep(3 * time.Second)
l.Done() // 原始值减一
fmt.Println("执行一下")
}()
l.Wait() // 加锁,当原始值为0的时候解锁
fmt.Println("执行完成")
Map
在进行并发的对同一个map进行读写操作的时候,会报错,使用
m := make(map[int]int)
go func() {
for {
m[1] = 1
}
}()
go func() {
for {
fmt.Println(m[1])
}
}()
for {
}
输出:
fatal error: concurrent map read and map write
使用sync包的map会自动对这个map进行加锁,所以这个map是线程安全的
m := &sync.Map{}
go func() {
for {
m.Store(1,1)
}
}()
go func() {
for {
fmt.Println(m.Load(1))
}
}()
time.Sleep(100)
输出:
...
1 true
1 true
1 true
1 true
1 true
1 true
...
Range
m := &sync.Map{}
m.Store(1,1)
m.Store(2,2)
m.Store(3,3)
m.Range(func(key, value any) bool {
// 这个Range接收一个func,参数就是key和value
fmt.Println(key,value)
time.Sleep(1000)
return true // 这里返回是true继续遍历,否则跳出
})
输出:
1 1
2 2
3 3
Pool
是一个共享的池子,所有人都可以存东西,取的时候随机
p := &sync.Pool{}
p.Put(1)
p.Put(2)
p.Put(3)
p.Put(4)
p.Put(5)
for i := 0; i < 6; i++ {
fmt.Println(p.Get())
}
输出:
1
5
4
3
2
<nil>
IO
io的几个接口
- Read(p []byte) (n int, err error)
p:把读取到的数据存在p字节组中,n:读取的字节码数量
- Write(p []byte) (n int, err error)
- Close
- Seek(offset int64, whence int)
这个函数是光标位置,就是对这个给文件操作的位置
offset:操作数,whence:从哪里开始
const ( SeekStart = 0 // seek relative to the origin of the file SeekCurrent = 1 // seek relative to the current offset SeekEnd = 2 // seek relative to the end )
其他的对文件的操作的包都会继承并实现这个接口
一个简易的dome:
f,err := os.OpenFile("./read.txt",os.O_CREATE|os.O_RDWR,0777) // os.OpenFile,打开文件,(路径,模式,权限)
/*
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
// The remaining values may be or'ed in to control behavior.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
*/
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
write:= bufio.NewWriter(f) //定义一个写入缓存区
read := bufio.NewReader(f) //定义一个读取
n := 0
for {
n++
str,_, err := read.ReadLine() //整行读取
if err != nil {
break
}
write.WriteString(strconv.Itoa(n)+" "+string(str)+"\n") // 写入缓存区
}
f.Seek(0,io.SeekStart) //定义光标位置,这里胸开始的位置,偏移为0
write.Flush() // 从缓存区直接写入到文件中
web基础
demo
server:
package main
import (
"fmt"
"net"
)
func main() {
tcpAddr ,_:= net.ResolveTCPAddr("tcp",":9999")
listen, _ := net.ListenTCP("tcp", tcpAddr)
for {
conn, err := listen.AcceptTCP()
if err != nil {
fmt.Println(err)
break
}
go handlerConnection(conn)
}
}
func handlerConnection(conn *net.TCPConn) {
for {
b := make([]byte, 1024)
n, _ := conn.Read(b)
fmt.Println(conn.RemoteAddr().String()+": "+string(b[:n]))
conn.Write([]byte("收到"+string(b[:n])))
}
}
client
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
tcpAddr ,_:= net.ResolveTCPAddr("tcp",":9999")
conn, _ := net.DialTCP("tcp", nil, tcpAddr)
for {
reader := bufio.NewReader(os.Stdin)
b, _:= reader.ReadString('\n')
conn.Write([]byte(b))
re := make([]byte, 1024)
n, _ := conn.Read(re)
if n == 0 {
fmt.Println("发送失败")
}
fmt.Println(conn.RemoteAddr().String()+": "+string(re[:n]))
}
}
RPC包
注意事项:
- Go的RPC只支持go写的系统
- 对函数的要求
- 首字母必须大写(公开的)
- 必须只有两个参数第一个参数是接收的参数,第二个参数是返回给客户端的参数,第二个参数必须是指针类型的
- 函数还要有一个返回值error
举例: func(t *T) MethonName(argType T1, replyType *T2) error{}
dome
server
package main
import (
"fmt"
"net"
"net/http"
"net/rpc"
)
type Server struct {
}
type Req struct {
NumOne int
NumTwo int
}
type Res struct {
NumTotal int
}
func (s *Server) Add(req Req, res *Res) error {
res.NumTotal = req.NumTwo + req.NumOne
return nil
}
func main() {
rpc.Register(new(Server))
rpc.HandleHTTP()
l, err := net.Listen("tcp",":8888")
if err != nil {
fmt.Println("失败!")
return
}
http.Serve(l, nil)
}
client
package main
import (
"fmt"
"net/rpc"
"time"
)
type Req struct {
NumOne int
NumTwo int
}
type Res struct {
NumTotal int
}
func main() {
req := Req{
NumOne: 1,
NumTwo: 2,
}
var res Res
client, err := rpc.DialHTTP("tcp", ":8888")
if err != nil {
fmt.Println("错误!")
return
}
//ca := client.Call("Server.Add", req, &res)
ca := client.Go("Server.Add", req, &res, nil)
//fmt.Println("这里会在拿到返回结果前面执行,可以做很多事情")
for {
select {
case <-ca.Done:
fmt.Printf("Arith: %d*%d=%d", req.NumOne, req.NumTwo, res)
return
default:
time.Sleep(1 * time.Second)
fmt.Println("等待")
}
}
}
websocket
是http的一种升级模式
使用包
require github.com/gorilla/websocket v1.5.0
基础http
package main
import "net/http"
func handler(w http.ResponseWriter, r *http.Request) {
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8888", nil)
}
升级结构
使用
var UP = websocket.Upgrader{}
Upgrader结构体
HandshakeTimeout: 0, //握手时间0为不限制
ReadBufferSize: 1024, //以字节为单位的IO缓存区,如果为0,则使用http服务器分配的缓冲区
WriteBufferSize: 1024, //以字节为单位的IO缓存区,如果为0,则使用http服务器分配的缓冲区
WriteBufferPool: nil, //用于写操作的缓冲池
Subprotocols: nil, //按照顺序指定服务器支持的协议
Error: nil, // 指定用于生成http错误响应的函数
CheckOrigin: nil, // 对过来的请求校验用
EnableCompression: false, // 指定服务器是否尝试根据进行协商消息压缩
demo
服务端
package main
import (
"bufio"
"fmt"
"github.com/gorilla/websocket"
"log"
"net/http"
"os"
"strings"
)
var (
UP = websocket.Upgrader{
ReadBufferSize: 1024, //以字节为单位的IO缓存区,如果为0,则使用http服务器分配的缓冲区
WriteBufferSize: 1024, //以字节为单位的IO缓存区,如果为0,则使用http服务器分配的缓冲区
}
// 注册的客户端连接
clients = make(map[string]*websocket.Conn)
// 用于广播消息的通道
broadcast = make(chan string)
)
func handler(w http.ResponseWriter, r *http.Request) {
conn, err := UP.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
return
}
fmt.Println(r.RemoteAddr + "建立连接")
// 关闭WebSocket连接
defer conn.Close()
// 注册客户端连接
_, mp, err := conn.ReadMessage()
if err != nil {
log.Fatal(r.RemoteAddr + "发生错误")
}
clients[string(mp)] = conn
//没有错误,建立for持续的拿消息
for {
_, p, e := conn.ReadMessage()
if e != nil {
break
}
conn.WriteMessage(websocket.TextMessage, []byte("服务器接收成功"))
fmt.Println(string(mp) + " 发出消息 -- " + string(p))
broadcast <- string(mp) + "/;;/" + string(p)
}
defer conn.Close()
fmt.Println("服务关闭")
}
func sand() {
for {
read := bufio.NewReader(os.Stdin)
l, _, _ := read.ReadLine()
//给每一个客户端发消息
broadcast <- "server" + "/;;/" + string(l)
}
}
// 广播消息
func handleMessages() {
for {
// 从广播通道中读取消息
message := <-broadcast
m := strings.Split(message, "/;;/")
s := strings.Split(m[1], ":")
if len(s) == 1 {
// 将消息发送给所有连接的客户端
for name, client := range clients {
err := client.WriteMessage(websocket.TextMessage, []byte("服务器群发消息--- "+m[1]))
if err != nil {
log.Println(err)
client.Close()
delete(clients, name)
}
}
} else {
if clients[s[0]] != nil {
//找到发送对象且在线
err := clients[s[0]].WriteMessage(websocket.TextMessage, []byte(m[0]+" 发送的消息 "+s[1]))
if err != nil {
log.Println(err)
clients[s[0]].Close()
delete(clients, s[0])
}
}
}
}
}
func main() {
//启动广播进程
go handleMessages()
// 服务端发送消息给全部在线客户端
go sand()
http.HandleFunc("/", handler)
err := http.ListenAndServe(":8888", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
客户端
package main
import (
"bufio"
"fmt"
"github.com/gorilla/websocket"
"log"
"os"
"strings"
)
func main() {
dl := websocket.Dialer{}
conn, _, err := dl.Dial("ws://127.0.0.1:8888", nil)
if err != nil {
log.Fatal(err)
return
}
conn.WriteMessage(websocket.TextMessage, []byte("crabin"))
go sand(conn)
for {
_, p, e := conn.ReadMessage()
if e != nil {
break
}
fmt.Println(string(p))
}
}
func sand(conn *websocket.Conn) {
for {
read := bufio.NewReader(os.Stdin)
l, _, _ := read.ReadLine()
if strings.Contains(string(l), ":") {
conn.WriteMessage(websocket.TextMessage, l)
} else {
fmt.Println("请输入正确的发送格式---目标:信息")
}
}
}
缺省
切片
数组的一部分,切片数据改变,数组也改变
a := []int{1,2,3}
cl := a[2:]
fmt.Println(cl)
cl[0] = 5
fmt.Println(cl)
fmt.Println(a)
注意
常识1
包里面使用大写开头的变量或者方法才能被其他文件引用(公有),否则就只能自己调用(即私有)
标签:err,int,fmt,学习,Println,func,go,conn From: https://www.cnblogs.com/crabin/p/17131418.html