1、
package main
import "fmt"
func func1() func(int) int {
sum:=0
return func(val int) int {
sum+=val
return sum
}
}
func printFunc1() {
sumFunc:=func1()
fmt.Println(sumFunc(1))
fmt.Println(sumFunc(2))
}
func main() {
printFunc1()
}
结果:结果保留在闭包函数中,
1 3
2、
package main
import "fmt"
func func2() (val int) {
val = 10
defer func() {
val+=1
}()
return val
}
func printFunc2() {
fmt.Println(func2())
}
func main() {
printFunc2()
}
结果:
11
3、
package main
import "fmt"
func func3() int {
val := 10
defer func() {
val+=1
}()
return val
}
func printFunc3() {
fmt.Println(func3())
}
func main() {
printFunc3()
}
结果:
10二、goroutine
打印出什么?为什么?怎么解决?
package main
import (
"fmt"
"time"
)
func main() {
data := make(map[int]int , 10)
for i:=1;i<=10;i++ {
data[i] = i
}
for key,value := range data{
go func() {
fmt.Println("k ->",key,"v ->",value)
}()
}
time.Sleep(time.Second*1)
}
结果:输出同个数据多次,原因是goroutine栈没有刷新导致的问题
k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 10 v -> 10 k -> 5 v -> 5 k -> 10 v -> 10
解决方法:
for key,value := range data{
go func(key,value int) {
fmt.Println("k ->",key,"v ->",value)
}(key,value)
}
三、defer
1、
package main
import "fmt"
func main() {
m:=10
defer fmt.Printf("first defer : %dn",+m)
m=100
defer fmt.Printf("second defer : %dn",+m)
}
结果:
second defer : 100 first defer : 10
2、
package main
import "fmt"
func func1() func() {
defer fmt.Println("before return")
return func(){
defer fmt.Println("in the return")
}
}
func main() {
m:=10
defer fmt.Printf("first defer : %dn",m) //5 10
m=100
defer func() {
fmt.Printf("second defer : %dn",m) //4 1000*10=10000
}()
m *= 10
defer fmt.Printf("second defer : %dn",m) //3 100*10=1000
funcVal := func1() //1 调用函数将返回的闭包函数赋给funcVal
funcVal() //2
}
结果:
before return in the return second defer : 1000 second defer : 1000 first defer : 10
3、
package main
import "fmt"
func func2() (sum int){
sumA := 100
sumB := 100
sum = sumA +sumB
defer func(){
defer fmt.Printf("func2 first : %dn",sum) //2000
}()
defer fmt.Printf("func2 second : %dn", sum) //200
return sum*10 //2000
}
func main() {
defer fmt.Printf("main : %dn",func2()) //1
}
结果:
func2 second : 200 func2 first : 2000 main : 2000
总结: defer是在return之前执行,defer 闭包函数内的值为指针。
四、slice扩容1、int64的
package main
import "fmt"
func main() {
var arr1 []int64
for i:=0; i<512; i++ {
arr1 = append(arr1,int64(i))
}
fmt.Printf("len = %d, cap = %dn",len(arr1),cap(arr1))
}
结果:
len = 512, cap = 512
当i<513的时候输出 len = 513, cap = 1024 当i<1024的时候输出 len = 1024, cap = 1024 当i<1025的时候输出 len = 1025, cap = 1280
2、int32
//int32: 1024*1.25*4=5120 查表大于5120且最接近的是5376,则5376/4=1344
func main() {
var arr1 []int32
for i:=0; i<1025; i++ {
arr1 = append(arr1,int32(i))
}
fmt.Printf("len = %d, cap = %dn",len(arr1),cap(arr1))
}
输出:
len = 1025, cap = 1344
3、批量append
//批量append
//1025*8=8200 查表 9472/8=1184
func main() {
var arr1 []int64
var arr2 []int64
for i:=0; i<1025; i++ {
arr1 = append(arr1,int64(i))
}
fmt.Printf("len = %d, cap = %dn",len(arr1),cap(arr1))
arr2 = append(arr2,arr1...)
fmt.Printf("len = %d, cap = %dn",len(arr2),cap(arr2))
}
输出
len = 1025, cap = 1280 len = 1025, cap = 1184
总结:
少于1024的双倍扩容,大于1024的1.25倍扩容 网上结论:1024*1.25=1280 实际结论与位数相关 一个一个append int32: 1024*1.25*4=5120 查表大于5120且最接近的是5376,则5376/4=1344 int64: 1024*1.25*8=10240 查表为10240,则10240/8=1280 批量append 1025*8=8200 查表 9472/8=1184
查表在runtime包下的sizeclasses.go下,查找的是左侧的第二栏,如下:
// Code generated by mksizeclasses.go; DO NOT EDIT.
//go:generate go run mksizeclasses.go
package runtime
// class bytes/obj bytes/span objects tail waste max waste min align
// 1 8 8192 1024 0 87.50% 8
// 2 16 8192 512 0 43.75% 16
// 3 24 8192 341 8 29.24% 8
// 4 32 8192 256 0 21.88% 32
// 5 48 8192 170 32 31.52% 16
// 6 64 8192 128 0 23.44% 64
// 7 80 8192 102 32 19.07% 16
// 8 96 8192 85 32 15.95% 32
// 9 112 8192 73 16 13.56% 16
// 10 128 8192 64 0 11.72% 128
// 11 144 8192 56 128 11.82% 16
// 12 160 8192 51 32 9.73% 32
// 13 176 8192 46 96 9.59% 16
// 14 192 8192 42 128 9.25% 64
// 15 208 8192 39 80 8.12% 16
// 16 224 8192 36 128 8.15% 32
// 17 240 8192 34 32 6.62% 16
// 18 256 8192 32 0 5.86% 256
// 19 288 8192 28 128 12.16% 32
// 20 320 8192 25 192 11.80% 64
// 21 352 8192 23 96 9.88% 32
// 22 384 8192 21 128 9.51% 128
// 23 416 8192 19 288 10.71% 32
// 24 448 8192 18 128 8.37% 64
// 25 480 8192 17 32 6.82% 32
// 26 512 8192 16 0 6.05% 512
// 27 576 8192 14 128 12.33% 64
// 28 640 8192 12 512 15.48% 128
// 29 704 8192 11 448 13.93% 64
// 30 768 8192 10 512 13.94% 256
// 31 896 8192 9 128 15.52% 128
// 32 1024 8192 8 0 12.40% 1024
// 33 1152 8192 7 128 12.41% 128
// 34 1280 8192 6 512 15.55% 256
// 35 1408 16384 11 896 14.00% 128
// 36 1536 8192 5 512 14.00% 512
// 37 1792 16384 9 256 15.57% 256
// 38 2048 8192 4 0 12.45% 2048
// 39 2304 16384 7 256 12.46% 256
// 40 2688 8192 3 128 15.59% 128
// 41 3072 24576 8 0 12.47% 1024
// 42 3200 16384 5 384 6.22% 128
// 43 3456 24576 7 384 8.83% 128
// 44 4096 8192 2 0 15.60% 4096
// 45 4864 24576 5 256 16.65% 256
// 46 5376 16384 3 256 10.92% 256
// 47 6144 24576 4 0 12.48% 2048
// 48 6528 32768 5 128 6.23% 128
// 49 6784 40960 6 256 4.36% 128
// 50 6912 49152 7 768 3.37% 256
// 51 8192 8192 1 0 15.61% 8192
// 52 9472 57344 6 512 14.28% 256
// 53 9728 49152 5 512 3.64% 512
// 54 10240 40960 4 0 4.99% 2048
// 55 10880 32768 3 128 6.24% 128
// 56 12288 24576 2 0 11.45% 4096
// 57 13568 40960 3 256 9.99% 256
// 58 14336 57344 4 0 5.35% 2048
// 59 16384 16384 1 0 12.49% 8192
// 60 18432 73728 4 0 11.11% 2048
// 61 19072 57344 3 128 3.57% 128
// 62 20480 40960 2 0 6.87% 4096
// 63 21760 65536 3 256 6.25% 256
// 64 24576 24576 1 0 11.45% 8192
// 65 27264 81920 3 128 10.00% 128
// 66 28672 57344 2 0 4.91% 4096
// 67 32768 32768 1 0 12.50% 8192
// alignment bits min obj size
// 8 3 8
// 16 4 32
// 32 5 256
// 64 6 512
// 128 7 768
// 4096 12 28672
// 8192 13 32768
const (
_MaxSmallSize = 32768
smallSizeDiv = 8
smallSizeMax = 1024
largeSizeDiv = 128
_NumSizeClasses = 68
_PageShift = 13
)
var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 24, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
var class_to_allocnpages = [_NumSizeClasses]uint8{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, 3, 1, 3, 2, 3, 4, 5, 6, 1, 7, 6, 5, 4, 3, 5, 7, 2, 9, 7, 5, 8, 3, 10, 7, 4}
var class_to_divmagic = [_NumSizeClasses]uint32{0, ^uint32(0)/8 + 1, ^uint32(0)/16 + 1, ^uint32(0)/24 + 1, ^uint32(0)/32 + 1, ^uint32(0)/48 + 1, ^uint32(0)/64 + 1, ^uint32(0)/80 + 1, ^uint32(0)/96 + 1, ^uint32(0)/112 + 1, ^uint32(0)/128 + 1, ^uint32(0)/144 + 1, ^uint32(0)/160 + 1, ^uint32(0)/176 + 1, ^uint32(0)/192 + 1, ^uint32(0)/208 + 1, ^uint32(0)/224 + 1, ^uint32(0)/240 + 1, ^uint32(0)/256 + 1, ^uint32(0)/288 + 1, ^uint32(0)/320 + 1, ^uint32(0)/352 + 1, ^uint32(0)/384 + 1, ^uint32(0)/416 + 1, ^uint32(0)/448 + 1, ^uint32(0)/480 + 1, ^uint32(0)/512 + 1, ^uint32(0)/576 + 1, ^uint32(0)/640 + 1, ^uint32(0)/704 + 1, ^uint32(0)/768 + 1, ^uint32(0)/896 + 1, ^uint32(0)/1024 + 1, ^uint32(0)/1152 + 1, ^uint32(0)/1280 + 1, ^uint32(0)/1408 + 1, ^uint32(0)/1536 + 1, ^uint32(0)/1792 + 1, ^uint32(0)/2048 + 1, ^uint32(0)/2304 + 1, ^uint32(0)/2688 + 1, ^uint32(0)/3072 + 1, ^uint32(0)/3200 + 1, ^uint32(0)/3456 + 1, ^uint32(0)/4096 + 1, ^uint32(0)/4864 + 1, ^uint32(0)/5376 + 1, ^uint32(0)/6144 + 1, ^uint32(0)/6528 + 1, ^uint32(0)/6784 + 1, ^uint32(0)/6912 + 1, ^uint32(0)/8192 + 1, ^uint32(0)/9472 + 1, ^uint32(0)/9728 + 1, ^uint32(0)/10240 + 1, ^uint32(0)/10880 + 1, ^uint32(0)/12288 + 1, ^uint32(0)/13568 + 1, ^uint32(0)/14336 + 1, ^uint32(0)/16384 + 1, ^uint32(0)/18432 + 1, ^uint32(0)/19072 + 1, ^uint32(0)/20480 + 1, ^uint32(0)/21760 + 1, ^uint32(0)/24576 + 1, ^uint32(0)/27264 + 1, ^uint32(0)/28672 + 1, ^uint32(0)/32768 + 1}
var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv + 1]uint8{32, 33, 34, 35, 36, 37, 37, 38, 38, 39, 39, 40, 40, 40, 41, 41, 41, 42, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 48, 48, 48, 49, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67}
五、nil是否一定相等
package main
import "fmt"
func main() {
var x *int = nil
var y interface{} = x
fmt.Println(x == y) //true
fmt.Println(x == nil) //true
fmt.Println(y == nil) //false
var z interface{} = nil
fmt.Println(z == nil) //true
fmt.Println(y == z) //false 由于type不同导致他们不相等
}
y == nil 为false的原因:
由于y被x强制转化为int类型,且值为nil,因此在比较y是否等于nil的时候,由于type为int,导致其为false。
总结:
interface的底层结构为:(在runtime包下的runtime2.go)
空接口是eface,非空接口是iface
例如:iface是带function的,eface是不带function的。
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}
六、并发测试
互斥锁不可重复上锁
package main
import (
"fmt"
"sync"
)
//互斥锁,不可重入锁 在一个goroutine下,重复上锁的话,就会发生panic
var mu sync.Mutex
var chain string
func main() {
chain = "main"
A()
fmt.Println(chain)
}
func A() {
mu.Lock()
defer mu.Unlock()
chain = chain + " --> A"
B()
}
func B() {
chain = chain + " --> B"
C()
}
func C() {
mu.Lock()
defer mu.Unlock()
chain = chain + " --> C"
}
结果:panic
原因:互斥锁,不可重入锁 在一个goroutine下,重复上锁的话,就会发生panic
package main
import (
"fmt"
"time"
)
func proc() {
panic("ok")
}
func main() {
go func() {
//1、在这里需要你写算法
//2、要求每秒调用一次proc函数
//3、要求程序不能退出
t := time.NewTicker(time.Second)
for {
select {
case <-t.C:
go func() {
defer func() {
if err := recover(); err!=nil{
fmt.Println(err)
}
}()
fmt.Println(time.Now())
proc()
}()
}
}
}()
select {}
}
输出
2022-06-01 19:43:09.9668789 +0800 CST m=+1.016162401 ok 2022-06-01 19:43:10.9661258 +0800 CST m=+2.015409301 ok 2022-06-01 19:43:11.9635083 +0800 CST m=+3.012791801 ok八、LRU缓存(leetcode算法题)
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。
解答:
//双向链表
type DLinkNode struct {
key,val int
pre,next *DLinkNode
}
type LRUCache struct {
size,capacity int
cache map[int]*DLinkNode
head,tail *DLinkNode
}
//初始化
func initDLinkNode(key,val int) *DLinkNode {
return &DLinkNode{key: key,val: val}
}
//构造
func Constructor(capacity int) LRUCache {
l := LRUCache{
capacity: capacity,
size: 0,
cache: map[int]*DLinkNode{},
head: initDLinkNode(0,0),
tail: initDLinkNode(0,0),
}
l.head.next = l.tail
l.tail.pre = l.head
return l
}
//移除节点
func removeNode(node *DLinkNode) {
node.pre.next = node.next
node.next.pre = node.pre
}
//移除尾部节点
func (this *LRUCache)removeTail() *DLinkNode{
node := this.tail.pre
removeNode(node)
return node
}
//添加节点到头部
//头指针(head)为空
func (this *LRUCache)addHead(node *DLinkNode) {
node.next = this.head.next
node.pre = this.head
this.head.next.pre = node
this.head.next = node
}
//移除头个节点
func (this *LRUCache)movetoHead(node *DLinkNode) {
removeNode(node)
this.addHead(node)
}
//获取节点的值
func (this *LRUCache) Get(key int) int {
if node,ok := this.cache[key]; ok{
this.movetoHead(node)
return node.val
}
return -1
}
//插入节点
func (this *LRUCache) Put(key int, value int) {
if node,ok := this.cache[key];ok {
node.val = value
this.movetoHead(node)
}else {
newNode := initDLinkNode(key,value)
this.addHead(newNode)
this.cache[key] = newNode
this.size++
if this.size > this.capacity {
tail :=this.removeTail()
this.size--
delete(this.cache,tail.key)
}
}
}
总结:LRU算法核心在于置换的实现
九、无重复最长子串
解答:
func lengthOfLongestSubstring(s string) int {
start := 0
end := 0
for i := 0; i< len(s);i++{
index := strings.Index(s[start:i],string(s[i]))
if index == -1 && (i+1)>end {
end = i + 1
}else {
start += index + 1
end += index + 1
}
}
return end -start
}
十、快速排序
解答:
package main
import (
"fmt"
)
func main() {
fmt.Println(QuickSort([]int{5,2,3,9,1,4,8,7}))
}
func QuickSort(nums []int) []int {
if len(nums) <=1 {
return nums
}
low := make([]int,0,0)
high := make([]int,0,0)
mid := make([]int,0,0)
flag := nums[0]
mid = append(mid,flag)
for i :=1; i
if nums[i]
low = append(low,nums[i])
}else if nums[i] >flag {
high = append(high,nums[i])
}else {
mid = append(mid,nums[i])
}
}
low,high = QuickSort(low),QuickSort(high)
return append(append(low,mid...),high...)
}
输出:
[1 2 3 4 5 7 8 9]十一、反转链表
解答:
func reverseList(head *ListNode) *ListNode {
cur := head
var pre *ListNode = nil
for cur != nil {
pre,cur,cur.Next = cur,cur.Next,pre //核心,记住下一个
}
return pre
}
十二、内存对齐
这两个结构体占用的内存大小一样吗?
package main
import (
"fmt"
"unsafe"
)
type DemoA struct {
A int8
B int64
C int16
}
type DemoB struct {
A int8
C int16
B int64
}
func main() {
fmt.Println(unsafe.Sizeof(DemoA{}))
fmt.Println(unsafe.Sizeof(DemoB{}))
}
输出:
24 16
原因:
解析:链接
十三、翻转字符串翻转字符串,可能包含有中文、数字、英文。(要求翻转原有字符串,不创建新的存储空间。
解答:
package main
import "fmt"
func main() {
fmt.Println(reverse("dlrow olleh"))
}
//翻转字符串,可能包含有中文、数字、英文。(要求翻转原有字符串,不创建新的存储空间)
func reverse(str string) string {
s := []rune(str)
for i,j :=0, len(s)-1; i
s[i],s[j] = s[j],s[i]
}
return string(s)
}
输出:
hello world十四、协程顺序执行问题
使用三个协程,每秒钟打印cat、dog、fish
顺序不能变化(协程1打印cat、协程2打印dong、协程3打印fish)
无限循环即可
解答:
package main
import (
"fmt"
"sync"
"time"
)
func cat(fishCH,catCH chan struct{}, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
for {
fmt.Println("cat")
catCH <- struct{}{}
<- fishCH
}
wg.Done()
}()
}
func dog(catCH,dogCH chan struct{}, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
for {
<- catCH
fmt.Println("dog")
dogCH <- struct{}{}
}
wg.Done()
}()
}
func fish(dogCH,fishCH chan struct{}, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
for {
<- dogCH
fmt.Println("fish")
time.Sleep(time.Second)
fishCH <- struct{}{}
}
wg.Done()
}()
}
func main() {
catCH := make(chan struct{})
dogCH := make(chan struct{})
fishCH := make(chan struct{})
wg := sync.WaitGroup{}
cat(fishCH,catCH,&wg)
dog(catCH,dogCH,&wg)
fish(dogCH,fishCH,&wg)
wg.Wait()
}
输出:
cat dog fish cat dog fish cat dog fish cat dog fish十五、Tag原理
package main
import (
"fmt"
"reflect"
)
type UserInfo struct {
Name string `bilibili:"BILIBLI_NAME" abc:"abc_name"`
PublicWX string `bilibili:"BILIBILI_PUBLICWX" abc:"abc_publicwx"`
}
func PrintTag(ptr interface{}) {
reType := reflect.TypeOf(ptr)
if reType.Kind() != reflect.Ptr || reType.Elem().Kind() != reflect.Struct {
panic("传入的参数不是结构体指针")
return
}
v := reflect.ValueOf(ptr).Elem()
fmt.Println(v)
for i := 0; i
field := v.Type().Field(i)
tag := field.Tag
labelTag := tag.Get("bilibili")
fmt.Println(labelTag)
labelTag = tag.Get("abc")
fmt.Println(labelTag)
}
}
func main() {
userInfo := &UserInfo{
Name: "golang",
PublicWX: "goland",
}
PrintTag(userInfo)
}
输出:
{golang goland}
BILIBLI_NAME
abc_name
BILIBILI_PUBLICWX
abc_publicwx
十六、golang中不会回收线程
原因:这是golang遗留下来的一个问题,解决这个问题相对比较麻烦,目前还没有解决
例子:
package main
import (
"fmt"
"net"
"runtime"
"runtime/pprof"
"sync"
)
var threadProfile = pprof.Lookup("threadcreate")
func main() {
fmt.Printf("协程执行之前的线程数:%dn",threadProfile.Count())
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++{
go func() {
defer wg.Done()
//以下语句进行强制回收线程,其实也就是将goroutine强制绑定在线程上,
//goroutine在退出的时候,如果没有去解锁线程,则线程会被操作系统终止
runtime.LockOSThread()
for j := 0;j<100;j++ {
_,err := net.LookupHost("www.baidu.com")
if err != nil {
panic(err)
}
}
}()
}
wg.Wait()
fmt.Printf("协程执行之后所剩下的线程数:%dn",threadProfile.Count())
}
强制回收:将goroutine强制绑定在线程上,goroutine在退出的时候,如果没有去解锁线程,则线程会被操作系统终止,因此调用多少次绑定,就要调用多少次解锁
未加时输出:
协程执行之前的线程数:6 协程执行之后所剩下的线程数:104
加之后输出:回收部分线程
协程执行之前的线程数:6 协程执行之后所剩下的线程数:54
参考视频:链接



