1.chan<- int是一个只能发送的通道,可以发送但是不能接收;
2.<-chan int是一个只能接收的通道,可以接收但是不能发送。
Go语言中的并发安全性和锁是实现并发控制的重要概念。下面是关于并发安全和锁的笔记:
-
并发安全性:
- 并发安全性是指在多个并发执行的goroutine中,共享的数据能够被正确地访问和操作,而不会出现数据竞争、内存泄漏或其他意外行为。
- 在Go语言中,通过使用通道(channel)和互斥锁(mutex)等机制,可以实现并发安全性。
-
互斥锁(Mutex):
-
互斥锁是一种常用的并发控制机制,用于保护共享资源,确保同一时间只有一个goroutine能够访问该资源。
-
Go语言中的
sync包提供了互斥锁的实现,可以使用sync.Mutex类型来创建互斥锁对象。 -
使用互斥锁的基本流程为:
- 在访问共享资源之前,调用互斥锁的
Lock方法获取锁。 - 在访问完成后,调用互斥锁的
Unlock方法释放锁。
- 在访问共享资源之前,调用互斥锁的
-
-
读写锁(RWMutex):
-
读写锁是一种特殊类型的锁,可以在多个读操作同时进行的情况下,防止写操作的并发访问。
-
Go语言中的
sync包提供了读写锁的实现,可以使用sync.RWMutex类型来创建读写锁对象。 -
使用读写锁的基本流程为:
- 对于读操作,调用读写锁的
RLock方法获取读锁,读取共享资源。 - 对于写操作,调用读写锁的
Lock方法获取写锁,修改共享资源。 - 在读或写操作完成后,分别调用读写锁的
RUnlock和Unlock方法释放锁。
- 对于读操作,调用读写锁的
-
-
原子操作(Atomic):
- 原子操作是一种不可分割的操作,可以确保在并发环境中对共享数据的操作是原子的、不会被打断的。
- Go语言中的
sync/atomic包提供了一组原子操作的函数,可以用于对数值类型进行原子操作,如原子增减、加载存储等。
并发安全性和锁是保证多个goroutine安全协同工作的重要手段。在编写并发程序时,需要考虑共享资源的访问限制,选择合适的锁机制来保护共享资源的并发访问,以避免数据竞争和其他并发问题。
以上是关于Go语言中并发安全性和锁的笔记。 channel + goroutine
package main
import (
"fmt"
"math/rand"
"runtime"
"time"
)
type Job struct {
Id int
Randnum int
}
type Res struct {
job *Job
sum int
}
func main() {
//job管道
jobChan := make(chan *Job, 123)
resultChan := make(chan *Res, 123)
//创建工作池
createPool(64, jobChan, resultChan)
//开个打印的协程
go func(resultChan chan *Res) {
//遍历结果管道打印
for res := range resultChan {
fmt.Printf("job is:%v randnum:%v ans:%d\n", res.job.Id, res.job.Randnum, res.sum)
time.Sleep(time.Second * 1)
}
}(resultChan)
var id int
//循环创建job 输入到管道
defer fmt.Println("job生产结束")
for {
id++
//生成randnum
r_num := rand.Int()
job := &Job{
Id: id,
Randnum: r_num,
}
jobChan <- job
}
time.Sleep(time.Second)
}
// arg1 开的协程的个数
func createPool(num int, jobChan chan *Job, resultChan chan *Res) {
//根据开的协程的个数,去跑运行
for i := 0; i < num; i++ {
go func(jobChan chan *Job, resultChan chan *Res) {
for job := range jobChan {
r_num := job.Randnum
var sum int
for r_num != 0 {
tmp := r_num % 10
sum += tmp
r_num /= 10
}
r := &Res{
job: job,
sum: sum,
}
resultChan <- r
}
}(jobChan, resultChan)
}
}
time
package main
import (
"fmt"
"time"
)
func main() {
timer1 := time.NewTimer(2 * time.Second)
t1 := time.Now()
fmt.Printf("t1:%v\n", t1)
t2 := <-timer1.C //阻塞进程 直到定时器触发并向通道发送一个时间值
fmt.Printf("t2:%v\n", t2)
}
并发安全和锁
package main
import (
"fmt"
"sync"
)
var x int64
var wg sync.WaitGroup
func add() {
for i := 0; i < 5000; i++ {
x++
}
wg.Done()
}
func main() {
wg.Add(2)
go add()
go add()
wg.Wait()
fmt.Printf("The ans is %v", x)
}
注意 sync包中提供了并发安全的Map var m = sync.Map{} 这个Map的使用不需要初始化key和value的类型,应该是动态初始化。
go中也是有原子操作以及c++中类似的CAS操作,compare_and_swap 举个例子 int63类型的value进行原子+1时使用如下
atomic.Addint64(&value,1)
Redis 操作笔记:
- Redis 是一个开源的高性能键值存储系统,可以用于缓存、数据库和消息队列等场景。
- 在 Go 语言中,可以使用第三方的 Redis 客户端库,如 go-redis、redigo 等,来与 Redis 进行交互。
- 使用 Redis 客户端库,可以进行常见的操作,如设置键值对、获取键值对、删除键、设置过期时间、发布订阅等。
time 库的笔记:
- time 是 Go 语言标准库提供的用于处理时间和日期的包。
- time 包提供了各种函数和方法,用于获取当前时间、解析时间字符串、格式化时间、计算时间差等操作。
- 可以使用 time.Now() 函数获取当前的本地时间;可以使用 time.Parse() 函数将字符串解析为时间对象;可以使用 time.Format() 函数将时间格式化为字符串。
- time 包还提供了一些时间间隔的类型和常用的操作,如计时器、定时器、睡眠等。
- 对于时间运算,可以使用 time.Add() 方法来增加或减少时间;使用 time.Since() 方法计算时间差;使用 time.Duration 表示时间间隔。
- 在处理时间时,需要注意时区、时间格式的选择,以及遵循时间操作的最佳实践,如使用 time.UTC 或 time.Local 设置时区,使用固定的时间格式进行解析和格式化 数据库的操作:redis+go
go连接redis服务器,参数,网络协议和地址
当使用Go语言中的Redis客户端库进行操作时,可以进行以下常见的操作:
-
设置键值对:
- 使用
SET命令来设置键值对,将指定的值与指定的键关联起来。例如:SET key value - 通过客户端库提供的方法,可以使用类似
Set(key, value)的函数来设置键值对。
- 使用
-
获取键值对:
- 使用
GET命令来获取键对应的值。例如:GET key - 通过客户端库提供的方法,可以使用类似
Get(key)的函数来获取键值对的值。
- 使用
-
删除键:
- 使用
DEL命令来删除指定的键。例如:DEL key - 通过客户端库提供的方法,可以使用类似
Del(key)的函数来删除指定的键。
- 使用
-
设置过期时间:
- 使用
EXPIRE命令来设置键的过期时间。例如:EXPIRE key seconds - 通过客户端库提供的方法,可以使用类似
Expire(key, duration)的函数来设置键的过期时间。
- 使用
-
发布订阅:
- Redis支持发布订阅模型,可以通过
PUBLISH命令发布消息,通过SUBSCRIBE命令订阅消息。 - 通过客户端库提供的方法,可以使用类似
Publish(channel, message)和Subscribe(channel)的函数来实现消息的发布和订阅。
- Redis支持发布订阅模型,可以通过
除了上述操作外,Redis还支持更多高级功能,如哈希表操作、列表操作、集合操作、事务等。可以根据具体需求使用相应的命令或客户端库提供的方法进行操作。
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
c, err := redis.Dial("udp", "127.0.0.1:30000")
if err != nil {
fmt.Println("conn redis failed,", err)
return
}
fmt.Println("redis conn success")
defer c.Close()
}
设置字段的过期时间
_, _ = c.Do("expire", "moxu", 10)
Redis还有Redia连接池的操作,类似于线程池 使用的时候进行取 使用完成后进行归还