1.下面代码输出什么,为什么
//make([]T, length, capacity) s1 := []int{1, 2, 3} fmt.Println(s1, "哈哈") //[1
2 3] s2 := s1 fmt.Println(s1, "哈哈") //[1 2 3] for i := 0; i < 3; i++ { s2[i] =
s2[i] + 1 } fmt.Println(s1) //[2 3 4] fmt.Println(s2) //[2 3 4] [1 2 3] 哈哈 [1 2
3] 哈哈 [2 3 4] [2 3 4]
注:引用就是同一份,相当于起了一个别名,就是多起了一个名字而已。
在Go语言中的引用类型有:映射(map),数组切片(slice),通道(channel),方法与函数。
整型,字符串,布尔,数组在当作参数传递时,是传递副本的内存地址,也就是值传递。
2.下面代码输出什么,为什么
func rmLast(a []int) { fmt.Println("a", a) a = a[:len(a)-1] for i := 0; i < 13;
i++ { a = append(a, 8) } fmt.Println("rm后a", a) // fmt.Println(len(a)) } func
updateLast(a []int) { fmt.Println("a", a) for i := 0; i < len(a); i++ { a[i] = a
[i] + 1 } fmt.Println("修改后a", a) // fmt.Println(len(a)) } func main() { xyz := [
]int{1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println("xyz", xyz) rmLast(xyz) fmt.Println(
"rm后xyz", xyz) updateLast(xyz) fmt.Println("修改后xyz", xyz) //[1 2 3 4 5 6 7 8 9]
} xyz [1 2 3 4 5 6 7 8 9] a [1 2 3 4 5 6 7 8 9] rm后a [1 2 3 4 5 6 7 8 8 8 8 8 8
8 8 8 8 8 8 8 8] rm后xyz [1 2 3 4 5 6 7 8 8] a [1 2 3 4 5 6 7 8 8] 修改后a [2 3 4 5
6 7 8 9 9] 修改后xyz [2 3 4 5 6 7 8 9 9]
注:函数内改切片的值,外部是可见的,改切片的长度外部是不可见的
3.下面代码输出什么,为什么
//n1是n2的底层数组 n1 := [3]int{1, 2, 3} n2 := n1[0:3] fmt.Println("下面是n1地址 ") for i
:= 0; i < len(n1); i++ { fmt.Printf("%p\n", &n1[i]) } fmt.Println(n1) fmt.
Println("下面是n2地址 ") for i := 0; i < len(n2); i++ { fmt.Printf("%p\n", &n2[i]) }
fmt.Println(n2) n2 = append(n2, 1) fmt.Println("下面是n1地址 ") for i := 0; i < len(
n1); i++ { fmt.Printf("%p\n", &n1[i]) } fmt.Println(n1) fmt.Println("下面是n2地址 ")
for i := 0; i < len(n2); i++ { fmt.Printf("%p\n", &n2[i]) } fmt.Println(n2)
下面是n1地址0xc000064140 0xc000064148 0xc000064150 [1 2 3] 下面是n2地址 0xc000064140
0xc000064148 0xc000064150 [1 2 3] 下面是n1地址 0xc000064140 0xc000064148 0xc000064150
[1 2 3] 下面是n2地址 0xc000090030 0xc000090038 0xc000090040 0xc000090048 [1 2 3 1]
4.下面代码输出什么,为什么
func defer_call(y int) { for i := 0; i < 5; i++ { defer fmt.Println("输出y+i", y+
i) fmt.Println("哈哈") defer fmt.Println("输出i ", i) } } func main() { defer_call(5
) } 哈哈 哈哈 哈哈 哈哈 哈哈 输出i 4 输出y+1 9 输出i 3 输出y+1 8 输出i 2 输出y+1 7 输出i 1 输出y+1 6 输出i 0
输出y+1 5 注:先执行"哈哈", 退出defer_call这个函数时,反序执行以下函数 fmt.Println("输出y+i",5)
fmt.Println("i",0) fmt.Println("输出y+i",6) fmt.Println(....)
fmt.Println("输出y+i",9) fmt.Println("i",4)
5.下面代码输出什么
func main() { for i := 0; i < 5; i++ { fmt.Println(i, "haha")
//匿名函数:匿名函数可以在声明后调用 go func() { time.Sleep(3 * time.Second) fmt.Println(i, "嗯嗯")
}() } time.Sleep(10 * time.Second) } 0 haha 1 haha 2 haha 3 haha 4 haha 5 嗯嗯 5
嗯嗯5 嗯嗯 5 嗯嗯 5 嗯嗯
6.下面代码输出什么
func main() { strs := []string{"one", "two", "three"} for _, s := range strs {
//1.主线程都快结束了(主线程跑到three了),并发出来的线程才刚开始 //2.这里匿名函数不传参的话,是共享的s的地址,所以打印出来的都是three go
func() { time.Sleep(1 * time.Second) fmt.Printf("%s ", s) }() } time.Sleep(3 *
time.Second) } three three three
7.下面代码输出什么
func main() { strs := []string{"one", "two", "three"} for _, s := range strs {
go func(s string) { time.Sleep(1 * time.Second) fmt.Printf("%s ", s) }(s) } time
.Sleep(3 * time.Second) } three one two one two three one three two
注:并发出来三个线程,哪个先结束不一定,所以输出不固定
8.下面代码输出什么
func main() { x := []string{"ha", "b", "c"} for v := range x { fmt.Print(v) } }
012
9.下面代码输出什么
type Slice []int func NewSlice() Slice { return make(Slice, 0) } func (s *Slice
) Add(elem int) *Slice { *s = append(*s, elem) fmt.Print(elem) return s } func
main() { s := NewSlice() defer s.Add(1).Add(2) s.Add(3) } 132
注:一个defer只能延迟调用一个函数,defer s.Add(1).Add(2),先执行参数部分,然后再延迟调用Add(2)
10.下面代码输出什么
package main import ( "fmt" ) func main() { defer_call() } func defer_call() {
defer func() { fmt.Println("打印前") }() defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }() panic("触发异常") }
考点:defer执行顺序
解答:
defer 是后进先出。
panic 需要等defer 结束后才会向上传递。 出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。

打印后
打印中
打印前
panic: 触发异常
11.下面代码输出什么
package main import ( "fmt" ) // 遍历切片的每个元素, 通过给定函数进行元素访问 func visit(list []int,
ffunc(int)) { for _, v := range list { f(v) } } func main() { // 使用匿名函数打印切片内容
visit([]int{1, 2, 3, 4}, func(v int) { fmt.Println(v) }) }
1
2
3
4
12.下面代码输出什么
package main import ( "fmt" "runtime" "sync" ) func main() {
//GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。 // 若 n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过
NumCPU 查询。 //本函数在调度程序优化后会去掉。 runtime.GOMAXPROCS(1) wg := sync.WaitGroup{} wg.Add
(20) for i := 0; i < 10; i++ { //主线程 go func() { //并发出来的线程 fmt.Println("A: ", i)
wg.Done() }() } for i := 0; i < 10; i++ { go func(i int) { fmt.Println("B: ", i
) wg.Done() }(i) } wg.Wait() }
考点:go执行的随机性和闭包
解答:
谁也不知道执行后打印的顺序是什么样的,所以只能说是随机数字。 但是A:均为输出10,B:从0~9输出(顺序不定)。 第一个go
func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。 故go func执行时,i的值始终是10。

第二个go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,go func内部指向值拷贝地址。
13.下面代码输出什么
package main import ( "fmt" "runtime" "sync" ) func main() {
//GOMAXPROCS设置可同时执行的最大CPU数,并返回先前的设置。 // 若 n < 1,它就不会更改当前设置。本地机器的逻辑CPU数可通过
NumCPU 查询。 //本函数在调度程序优化后会去掉。 runtime.GOMAXPROCS(2) wg := sync.WaitGroup{} wg.Add
(3) for i := 0; i < 10; i++ { //主线程 go func() { //并发出来的线程 fmt.Println("A: ", i)
wg.Done() }() } wg.Wait() wg.Add(7) wgg := sync.WaitGroup{} wgg.Add(5) for i :=
0; i < 10; i++ { go func(i int) { fmt.Println("B: ", i) wgg.Done() }(i) } wgg.
Wait() }
14.下面代码会触发异常吗?请详细说明
package main import ( "fmt" "runtime" ) func main() { runtime.GOMAXPROCS(1)
int_chan:= make(chan int, 1) string_chan := make(chan string, 1) int_chan <-1
string_chan<-"hello" select { case value := <-int_chan: fmt.Println(value) case
value:= <-string_chan: panic(value) } }
考点:select随机性
解答:
select会随机选择一个可用通用做收发操作。 所以代码是有肯触发异常,也有可能不会。 单个chan如果无缓冲时,将会阻塞。但结合
select可以在多个chan间等待执行。有三点原则:

select 中只要有一个case能return,则立刻执行。
当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
如果没有一个case能return则可以执行”default”块。
15.下面代码有什么问题,如何修改
package main import ( "fmt" "sync" ) type UserAges struct { ages map[string]int
sync.Mutex } func (ua *UserAges) Add(name string, age int) { ua.Lock() defer ua
.Unlock() ua.ages[name] = age } func (ua *UserAges) Get(name string) int { if
age, ok := ua.ages[name]; ok { return age } return -1 } func main() { var
userAges UserAges userAges.Add("lisa", 24) userAges.Get("lisa") fmt.Println(
userAges.ages) }
panic: assignment to entry in nil map

goroutine 1 [running]:
main.(*UserAges).Add(0xc0000521c0, 0x4c492f, 0x4, 0x18)
C:/Users/zyq/go/src/yj/ra.go:17 +0x98
main.main()
C:/Users/zyq/go/src/yj/ra.go:28 +0x69
exit status 2
修改后:
func (ua *UserAges) Add(name string, age int) { ua.ages = make(map[string]int)
ua.Lock() defer ua.Unlock() ua.ages[name] = age }
输出结果:
map[lisa:24]
16.下面代码输出什么,为什么
package main import ( "fmt" "sync" ) type threadSafeSet struct { sync.RWMutex s
[]interface{} } func (set *threadSafeSet) Iter() <-chan interface{} { // ch :=
make(chan interface{}) // 解除注释看看! ch := make(chan interface{}, len(set.s)) go
func() { set.RLock() for _, elem := range set.s { ch <- elem fmt.Println("Iter:"
, elem) } close(ch) set.RUnlock() }() return ch } func main() { th :=
threadSafeSet{ s: []interface{}{"1", "2"}, } v := <-th.Iter() fmt.Println(v) }
Iter: 1
Iter: 2
1
解答:ch := make(chan interface{}, len(set.s)) 每次都会分配一个新的channel,v :=
<-th.Iter()只传了一个值,所以v是数组s的第一个value
17.以下代码输出什么?为什么?
package main import ( "fmt" ) type People interface { Show() } type Student
struct{} func (stu *Student) Show() { } func live() People { var stu *Student
return stu } func main() { if live() == nil { fmt.Println("AAAAAAA") } else {
fmt.Println("BBBBBBB") } }
输出:
BBBBBBB

18.以下代码输出什么?为什么?
package main func main() { i := GetValue() switch i.(type) { case int: println(
"int") case string: println("string") case interface{}: println("interface")
default: println("unknown") } } func GetValue() int { return 1 }
解析
考点:type

编译失败,因为type只能使用在interface
修改后:
package main func main() { i := GetValue() switch i.(type) { case int: println(
"int") case string: println("string") case interface{}: println("interface")
default: println("unknown") } } func GetValue() interface{} { return 1 }
19.以下代码输出什么?为什么?
package main import "fmt" func main() { s1 := []int{1, 2, 3} s2 := []int{4, 5}
s1= append(s1, s2...) fmt.Println(s1) fmt.Println(s2) var a = []int{1, 2, 3} a =
append([]int{0}, a...) fmt.Println(a) a = append([]int{-3, -2, -1}, a...) fmt.
Println(a) }
[1 2 3 4 5]
[4 5]
[0 1 2 3]
[-3 -2 -1 0 1 2 3]
考点:
1.追加一个切片, 切片需要解包s1 = append(s1, s2…)
2.除了在切片的尾部追加,我们还可以在切片的开头添加元素
20.以下代码输出什么?为什么?
package main import "fmt" func GetValue(m map[int]string, id int) (string, bool
) { if _, exist := m[id]; exist { return "存在数据", true } return "", false } func
main() { intmap := map[int]string{ 1: "a", 2: "bb", 3: "ccc", } v, err :=
GetValue(intmap, 3) fmt.Println(v, err) }
存在数据 true
考点:map的key是否存在
21.以下代码输出什么?为什么?
package main func DeferFunc1(i int) (t int) { t = i defer func() { t += 3 }()
return t } func DeferFunc2(i int) int { t := i defer func() { t += 3 }() return
t} func DeferFunc3(i int) (t int) { defer func() { t += i }() return 2 } func
main() { println(DeferFunc1(1)) println(DeferFunc2(1)) println(DeferFunc3(1)) }
4
1
3
考点:
这个题的重点在于返回值有没有名字,有名字的话,返回值受defer里的func的影响,没有名字的话不受影响
22.以下代码输出什么?为什么?
package main import "fmt" const ( x = iota y z = "zz" k p = iota c d = "111" f
) func main() { fmt.Println(x, y, z, k, p, c, d, f) }
0 1 zz zz 4 5 111 111
考点:
在常量声明中,预声明的标识符 iota表示连续的无类型整数 常量。它的值是该
常量声明中相应ConstSpec的索引,从零开始。它可以用来构造一组相关的常量:

const(
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2


const(
a = 1 << iota // a == 1(iota == 0)
b = 1 << iota // b == 2(iota == 1)
c = 3 // c == 3(iota == 2,未使用)
d = 1 << iota // d == 8(iota == 3)


const(
u = iota * 42 // u == 0(无类型整数常量)
v float64 = iota * 42 // v == 42.0(float64常数)
w = iota * 42 // w == 84(无类型整数常量)

23.以下代码输出什么?为什么
package main var size = 1024 var max_size = size * 2 func main() { println(size
, max_size) }
extra expression in var declaration
考点:变量简短模式
变量简短模式限制:
定义变量同时显式初始化
不能提供数据类型
只能在函数内部使用
var a int var a = 1 a:=1
24.以下代码能输出吗?为什么
package main import"fmt" func main() { type MyInt1 int type MyInt2 = int var i
int =9 var i1 MyInt1 = i var i2 MyInt2 = i fmt.Println(i1,i2) }
cannot use i (type int) as type MyInt1 in assignment
考点:
基于一个类型创建一个新类型,称之为defintion;基于一个类型创建一个别名,称之为alias。
MyInt1为称之为defintion,虽然底层类型为int类型,但是不能直接赋值,需要强转; MyInt2称之为alias,可以直接赋值。
25.以下代码能输出吗?为什么
package main import "fmt" type User struct { } type MyUser1 User type MyUser2 =
Userfunc (i MyUser1) m1() { fmt.Println("MyUser1.m1") } func (i User) m2() {
fmt.Println("User.m2") } func main() { var i1 MyUser1 var i2 MyUser2 i1.m1() i2.
m2() i1.m2() }
输出:
MyUser1.m1
User.m2
i1.m2()是不能执行的,因为MyUser1没有定义该方法。
考点:
因为MyUser2完全等价于User,所以具有其所有的方法,并且其中一个新增了方法,另外一个也会有。
26.使用WaitGroup并发计算两组数据的和
package main import ( "fmt" "sync" ) func main() { wg := sync.WaitGroup{} var
xValueint var iValue int wg.Add(2) //开两个进程 go func() { for x := 0; x <= 50; x++
{ xValue += x } fmt.Println("xValue: ", xValue) wg.Done()
//放在进程里面最后,确认这个进程做完了计数器减一 }() //wg.Done() 如果done放在这里的话,不能确认上边的进程做了还是没做,都会减一 go
func() { for i := 51; i <= 100; i++ { iValue += i } fmt.Println("iValue: ",
iValue) wg.Done() }() wg.Wait() fmt.Println("sumValue", xValue+iValue) }
iValue: 3775
xValue: 1275
sumValue 5050
27.使用通道并发计算两组数据的和
package main import ( "fmt" ) func main() { c := make(chan int, 2) go func() {
var xValue int for x := 0; x <= 50; x++ { xValue += x } c <- xValue }() go func(
) { var iValue int for i := 51; i <= 100; i++ { iValue += i } c <- iValue }() x,
y:= <-c, <-c fmt.Println("sumValue", x+y) }
sumValue 5050
28.下面代码输出什么,为什么
package main func main() { done := make(chan struct{}) //结束事件 c := make(chan
string) //数据传输通道 go func() { s := <-c //接受消息 println(s) close(done)
//关闭通道,作为结束通知 }() c <- "hi!" //发送消息 <-done //阻塞,直到所有数据或管道关闭 }
hi!
29.下面代码输出什么,为什么
package main import ( "sync" "time" ) func main() { var wg sync.WaitGroup ready
:= make(chan struct{}) for i := 0; i < 3; i++ { wg.Add(1) go func(id int) {
defer wg.Done() println(id, ":ready.") <-ready //因为取不到,所以阻塞 println(id, ":
running...") }(i) } time.Sleep(time.Second) println("ready?Go!") close(ready)
//close之后,关闭通道解除阻塞 wg.Wait() }
0 :ready.
1 :ready.
2 :ready.
ready?Go!
2 : running…
1 : running…
0 : running…
30.下面代码输出什么,为什么
package main func main() { done := make(chan struct{}) //用于结束事件 c := make(chan
int) //数据传输通道 go func() { defer close(done) //通知关闭 for x := range c {
//循环读取消息直到通道被关闭 println(x) } }() c <- 1 c <- 2 c <- 3 close(c) //通道关闭解除阻塞 <-done
//阻塞,直到有数据或通知关闭 }
1
2
3
31.下面代码输出什么,为什么
package main func main() { done := make(chan struct{}) //用于结束事件 c := make(chan
int) //数据传输通道 go func() { defer close(done) //通知关闭 for { x, ok := <-c if !ok {
//据此判断通道是否被关闭 return } println(x) } //通道关闭,循环结束 }() c <- 1 c <- 2 c <- 3 close(c
) //通道关闭解除阻塞 <-done //阻塞,直到有数据或通知关闭 }
1
2
3
32.下面代码输出什么,为什么
package main func main() { c := make(chan int, 3) //数据传输通道 c <- 10 c <- 20
close(c) for i := 0; i < cap(c)+1; i++ { x, ok := <-c println(i, ":", ok, x) } }
0 : true 10
1 : true 20
2 : false 0
3 : false 0
33.下面代码输出什么,为什么
如果同时处理多个通道,可选用select语句,他会随机选用一个可用通道做收发操作
package main import "sync" func main() { var wg sync.WaitGroup wg.Add(2) a, b
:= make(chan int), make(chan int) go func() { //接收端 defer wg.Done() for { var (
namestring x int ok bool ) select { //随机选择可用channel接收数据 case x, ok = <-a: name =
"a" case x, ok = <-b: name = "b" } if !ok { return //如果任一通道关闭,则终止接收 } println(
name, x) //输出接收的数据信息 } }() go func() { //发送端 defer wg.Done() defer close(a)
defer close(b) for i := 0; i < 10; i++ { select { //随机选择发送的channel case a <- i:
case b <- i * 10: } } }() wg.Wait() }
输出一
C:\Users\zyq\go\src\LearnGoLang\learn>go run hello.go
b 0
a 1
a 2
a 3
b 40
b 50
b 60
a 7
a 8
a 9
输出二
C:\Users\zyq\go\src\LearnGoLang\learn>go run hello.go
a 0
b 10
b 20
b 30
a 4
a 5
b 60
b 70
b 80
a 9
输出…
34.下面代码输出什么,为什么
通道默认是双向的,并不区分发送和接收端,但某些时候我们可以限制收发操作的方向来获得更严谨的操作逻辑。
通常使用类型转换来获取单向通道,并分别赋予操作双方。
package main import "sync" func main() { var wg sync.WaitGroup wg.Add(2) c :=
make(chan int) var send chan<- int = c //仅发送 var recv <-chan int = c //仅接收 go
func() { //接收端 defer wg.Done() for x := range recv { println(x) } }() go func()
{ //发送端 defer wg.Done() defer close(c) for i := 0; i < 3; i++ { send <- i } }()
wg.Wait() }
0
1
2
注意:
1.不能在单向通上做逆向操作
2.close()不能用于接收端
3.无法将单向通道重新转换回去
35.下面代码输出什么,为什么
问题:通道能传slice吗
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add
(2) a, b := make(chan []int), make(chan []int) go func() { //接收端 defer wg.Done()
for { var ( name string x []int ok bool ) select { //随机选择可用channel接收数据 case x,
ok= <-a: name = "a" case x, ok = <-b: name = "b" } if !ok { return
//如果任一通道关闭,则终止接收 } x[0] = 99 fmt.Println(name, x) //输出接收的数据信息 } }() i := []int{1
, 2, 3, 4} go func() { //发送端 defer wg.Done() defer close(a) defer close(b) fmt.
Println(i) select { //随机选择发送的channel case a <- i: } }() wg.Wait() fmt.Println(i)
}
[1 2 3 4]
a [99 2 3 4]
[99 2 3 4]
36.第33题需要怎么改满足,等待全部通道消息处理结束,而不是任一通道关闭就终止接收
提示:如要等全部通道消息处理结束,可将已完成通道设置为nil,这样它就会被阻塞,不再被select选中。
package main import "sync" func main() { var wg sync.WaitGroup wg.Add(3) a, b
:= make(chan int), make(chan int) go func() { //接收端 defer wg.Done() for { select
{ //随机选择可用channel接收数据 case x, ok := <-a: if !ok { a = nil break
//用于循环语句中跳出循环,并开始执行循环之后的语句。 //break 在 switch(开关语句)中在执行一条 case 后跳出语句的作用。 }
println("a", x) case x, ok := <-b: if !ok { b = nil break } println("b", x) } if
a== nil && b == nil { //全部结束,退出循环 return } } }() go func() { //发送端a defer wg.
Done() defer close(a) for i := 0; i < 3; i++ { a <- i } }() go func() { //发送端b
defer wg.Done() defer close(b) for i := 0; i < 3; i++ { b <- i * 10 } }() wg.
Wait() }
a 0
b 0
b 10
a 1
a 2
b 20
37.下面代码输出什么,为什么
如果是同一通道,也会随机选择case执行
package main import "sync" func main() { var wg sync.WaitGroup wg.Add(2) c :=
make(chan int) go func() { //接收端 defer wg.Done() for { var ( v int ok bool )
select { //随机选择可用channel接收数据 case v, ok = <-c: println("a1:", v) case v, ok = <-
c: println("a2:", v) } if !ok { return //如果任一通道关闭,则终止接收 } } }() go func() {
//发送端 defer wg.Done() defer close(c) for i := 0; i < 10; i++ { select {
//随机选择发送的channel case c <- i: case c <- i * 10: } } }() wg.Wait() }
a1: 0
a2: 10
a1: 20
a1: 30
a1: 40
a1: 5
a1: 6
a2: 70
a1: 80
a1: 9
a2: 0
38.下面代码输出什么,为什么
package main func main() { done := make(chan struct{}) data := []chan int{ make
(chan int, 3), //数据缓冲区 } go func() { defer close(done)//关闭通道,结束阻塞 for i := 0; i
< 10; i++ { select { case data[len(data)-1] <- i: dafault: data = append(data,
make(chan int, 3)) } } }() <-done//阻塞 for i := 0; i < len(data); i++ { c := data
[i] close(c) for x := range c { println(x) } } }
39.下面代码输出什么,为什么
通常使用工厂方法将goroutine和通道绑定
package main import "sync" type receiver struct { sync.WaitGroup data chan int
} func newReceiver() *receiver { r := &receiver{ data: make(chan int), } r.Add(1
) go func() { //接收端 defer r.Done() for x := range r.data { //接收消息直到通道被关闭 println
("recv:", x) } }() return r } func main() { r := newReceiver() r.data <- 1 //发送端
r.data <- 2 close(r.data) //关闭通道,发出结束通知 r.Wait() //等待接收者处理结束 }
recv: 1
recv: 2
40.下面代码输出什么,为什么
用通道实现信号量
package main import ( "fmt" "sync" "runtime" "time" ) func main(){ runtime.
GOMAXPROCS(4) var wg sync.WaitGroup sem:=make(chan struct{},2)//最多允许两个并发同时执行 for
i:=0;i<5;i++{ wg.Add(1) go func(id int){ defer wg.Done() sem<-struct{}{}
//acquire:获取信号 defer func(){<-sem}()//release:释放信号 time.Sleep(time.Second*2) fmt
.Println(id,time.Now().Unix()) }(i) } wg.Wait() }
0 1599985509
4 1599985509
2 1599985511
1 1599985511
3 1599985513
41.下面代码输出什么,为什么
标准库time提供了timeout和tick channel实现
package main import ( "fmt" "time" "os" ) func main(){ go func(){ for{ select{
case <-time.After(time.Second*5): //func After(d Duration) <-chan Time
//After会在另一线程经过时间段d后向返回值发送当时的时间。等价于NewTimer(d).C。 fmt.Println("timeout...") os.
Exit(0) // Exit让当前程序以给出的状态码code退出。一般来说, //状态码0表示成功,非0表示出错。程序会立刻终止,defer的函数不会被执行。
} } }() go func(){ tick:=time.Tick(time.Second) for{ select{ case <-tick: fmt.
Println(time.Now().Unix()) } } }() <-(chan struct{})(nil)//直接用nil channel阻塞进程 }
42.下面代码输出什么,为什么
通道并非用来取代锁的,它们有各自不同的使用场景。通道倾向于解决逻辑层次的并发处理架构,而锁则用来保护局部范围内的数据安全。
package main import ( "sync" "time" ) type data struct { sync.Mutex } func (d
data) test(s string) { d.Lock() defer d.Unlock() for i := 0; i < 5; i++ {
println(s, i) time.Sleep(time.Second) } } func main() { var wg sync.WaitGroup wg
.Add(2) var d data go func() { defer wg.Done() d.test("read") }() go func() {
defer wg.Done() d.test("write") }() wg.Wait() }
write 0
read 0
read 1
write 1
read 2
write 2
read 3
write 3
read 4
write 4

技术
©2020 ioDraw All rights reserved
python简单小游戏代码-10分钟用Python编写一个贪吃蛇小游戏,简单Linux之父:C++语言很烂 不会改用其重写Linux内核webpack配置postcss-loader无效简单的学生成绩管理系统歌词格式转化,trc转lrcGO语言学习笔记【webpack】DLL plugin原理分析伪造ACK实现TCP数据注入调研组织结构图消息称华为招聘半导体设备人才 网友:光刻机是刚需