runtime
调度器是个非常有用的东西,关于 runtime
包几个方法:
cpu
以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行CPU
核数量CPU
核数goroutine
(但是 defer
语句会照常执行)package main
import (
"time"
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(2)
say2("hello", &wg)
say2("world", &wg)
fmt.Println("over!")
}
func say2(s string, waitGroup *sync.WaitGroup) {
defer waitGroup.Done()
for i := 0; i < 3; i++ {
fmt.Println(s)
}
}
输出
hello
hello
hello
world
world
world
over!
对于一个整数类型 T
, sync/atomic
标准库包提供了下列原子操作函数。 其中 T
可以是内置 int32
、 int64
、 uint32
、 uint64
和 uintptr
类型
func AddT(addr *T, delta T)(new T)
func LoadT(addr *T) (val T)
func StoreT(addr *T, val T)
func SwapT(addr *T, new T) (old T)
func CompareAndSwapT(addr *T, old, new T) (swapped bool)
sync/atomic
标准库包也提供了一个 Value
类型。以它为基的指针类型 *Value
拥有两个方法: Load
和 Store
。 Value
值用来原子读取和修改任何类型的Go值。
func (v *Value) Load() (x interface{})
func (v *Value) Store(x interface{})
一旦 v.Store
方法( (v).Store
的简写形式)被曾经调用一次,则传递给值 v
的后续方法调用的实参的具体类型必须和传递给它的第一次调用的实参的具体类型一致; 否则,将产生一个恐慌。 nil
接口类型实参也将导致 v.Store()
方法调用产生恐慌。
比如:
package main
import (
"fmt"
"sync/atomic"
)
func main() {
type T struct{ a, b, c int }
var ta = T{1, 2, 3}
var v atomic.Value
v.Store(ta)
var tb = v.Load().(T)
fmt.Println(tb) // {1 2 3}
fmt.Println(ta == tb) // true
v.Store("hello") // 将导致一个恐慌
}
输出结果
goroutine 1 [running]:
sync/atomic.(*Value).Store(0x14000110210, {0x102f47900, 0x102f58038})
/opt/homebrew/Cellar/go@1.17/1.17.10/libexec/src/sync/atomic/value.go:77 +0xf4
main.main()
/Users/tomxiang/github/go-demo/hello/routine/routine07.go:17 +0x218
Process finished with the exit code 2
一个 CompareAndSwapT
函数调用传递的旧值和目标值的当前值匹配的情况下才会将目标值改为新值,并返回 true
;否则立即返回 false
。
import (
"fmt"
"sync/atomic"
)
func main() {
type T struct{ a, b, c int }
var x = T{1, 2, 3}
var y = T{4, 5, 6}
var z = T{7, 8, 9}
var v atomic.Value
v.Store(x)
fmt.Println(v) // {{1 2 3}}
old := v.Swap(y)
fmt.Println("old:", old)
fmt.Println("v:", v) // {{4 5 6}}
fmt.Println("old.(T)", old.(T)) // {1 2 3}
swapped := v.CompareAndSwap(x, z)
fmt.Println(swapped, v) // false {{4 5 6}}
swapped = v.CompareAndSwap(y, z)
fmt.Println(swapped, v) // true {{7 8 9}}
}
输出结果
{{1 2 3}}
old: {1 2 3}
v: {{4 5 6}}
old.(T) {1 2 3}
false {{4 5 6}}
true {{7 8 9}}
Gosched
切换任务mutex.Lock
// Package main 这个示例程序展示如何使用互斥锁来
// 定义一段需要同步访问的代码临界区
// 资源的同步访问
package main
import (
"fmt"
"runtime"
"sync"
)
var (
// counter是所有goroutine都要增加其值的变量
counter int
// wg用来等待程序结束
wg sync.WaitGroup
// mutex 用来定义一段代码临界区
mutex sync.Mutex
)
// main 是所有Go程序的入口
func main() {
// 计数加2,表示要等待两个goroutine
wg.Add(2)
// 创建两个goroutine
go incCounter(1)
go incCounter(2)
// 等待goroutine结束
wg.Wait()
fmt.Printf("Final Counter: %d\n", counter)
}
// incCounter 使用互斥锁来同步并保证安全访问,
// 增加包里counter变量的值
func incCounter(id int) {
// 在函数退出时调用Done来通知main函数工作已经完成
defer wg.Done()
for count := 0; count < 2; count++ {
// 同一时刻只允许一个goroutine进入
// 这个临界区
mutex.Lock()
{ // 使用大括号只是为了让临界区看起来更清晰,并不是必需的。
// 捕获counter的值
value := counter
// 当前goroutine从线程退出,并放回到队列
runtime.Gosched()
// 增加本地value变量的值
value++
// 将该值保存回counter
counter = value
}
mutex.Unlock()
// 释放锁,允许其他正在等待的goroutine
// 进入临界区
}
}
输出结果:
4
对 counter 变量的操作在第 46 行和第 60 行的 Lock() 和 Unlock() 函数调用定义的临界区里被保护起来。
同一时刻只有一个 goroutine 可以进入临界区。之后,直到调用 Unlock() 函数之后,其他 goroutine 才能进入临界区。当第 52 行强制将当前 goroutine 退出当前线程后,调度器会再次分配这个 goroutine 继续运行。当程序结束时,我们得到正确的值 4,竞争状态不再存在。
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
var mutex sync.Mutex
wait := sync.WaitGroup{}
fmt.Println("Locked Start")
mutex.Lock()
for i := 1; i <= 5; i++ {
wait.Add(1)
go func(i int) {
fmt.Println("Not lock:", i)
mutex.Lock()
fmt.Println("Lock:", i)
time.Sleep(time.Second)
fmt.Println("Unlock:", i)
mutex.Unlock()
defer wait.Done()
}(i)
}
time.Sleep(time.Second)
fmt.Println("Unlocked finish")
mutex.Unlock()
wait.Wait()
}
输出结果
Locked Start
Not lock: 5
Not lock: 1
Not lock: 2
Not lock: 3
Not lock: 4
Unlocked finish
Lock: 5
Unlock: 5
Lock: 1
Unlock: 1
Lock: 2
Unlock: 2
Lock: 3
Unlock: 3
Lock: 4
Unlock: 4
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有