**1**.写出代码运行结果,如有错误则指出
(1)
```go
package main
import "fmt"
func main() {
/*
先defer的后执行
recover后输出panic中的信息
*/
defer func() {
if err := recover(); err != nil {
fmt.Print(err)
} else {
fmt.Print("no")
}
}()
defer
func() {
panic("1111111111111")
}()
panic("22222222222")
}```
**解题思路**:先defer的语句后执行,即假如你defer了多个语句,执行时会按逆序执行,所以这段代码执行顺序为
先 `panic("22222222222")`,
再
```go
defer
func() {
panic("1111111111111")
}()```
最后
``` go
defer func() {
if err := recover(); err != nil {
fmt.Print(err)
} else {
fmt.Print("no")
}
}()```
所以得出结果 输出 1111111111111
(2)
```go
package main
import "fmt"
var c1 =make(chan int)
var c2 =make(chan int)
func main() {
go func() {
fmt.Println("111111111111")
c1<-<-c2
}()
go func() {
c1<-<-c2
fmt.Println("22222222222")
}()
<-c1
}```
**解题思路**:无缓存的Channel发送接收都为阻塞,
**2**.简述go中的channel和mutex锁机制的原理异同与使用场景
golang中的同步是通过sync.WaitGroup来实现的.WaitGroup的功能:它实现了一个类似队列的结构,可以一直向队列中添加任务,当任务完成后便从队列中删除,如果队列中的任务没有完全完成,可以通过Wait()函数来出发阻塞,防止程序继续进行,直到所有的队列任务都完成为止.WaitGroup总共有三个方法:Add(delta int), Done(), Wait()。Add:添加或者减少等待goroutine的数量Done:相当于Add(-1)Wait:执行阻塞,直到所有的WaitGroup数量变成0
**使用场景**:
程序中需要并发,需要创建多个goroutine,并且一定要等这些并发全部完成后才继续接下来的程序执行.WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,而不需要sleep一个固定的时间来等待.但是其缺点是无法指定固定的goroutine数目.
Channel机制:
相对sync.WaitGroup而言,golang中利用channel实习同步则简单的多.channel自身可以实现阻塞,其通过<-进行数据传递,channel是golang中一种内置基本类型,对于channel操作只有4种方式:
创建channel(通过make()函数实现,包括无缓存channel和有缓存channel);
向channel中添加数据(channel<-data);
从channel中读取数据(data<-channel);
关闭channel(通过close()函数实现,关闭之后无法再向channel中存数据,但是可以继续从channel中读取数据)
channel分为有缓冲channel和无缓冲channel,两种channel的创建方法如下:
var ch = make(chan int) //无缓冲channel,等同于make(chan int ,0)
var ch = make(chan int,10) //有缓冲channel,缓冲大小是5
其中无缓冲channel在读和写是都会阻塞,而有缓冲channel在向channel中存入数据没有达到channel缓存总数时,可以一直向里面存,直到缓存已满才阻塞.由于阻塞的存在,所以使用channel时特别注意使用方法,防止死锁的产生.
**golang 并发总结**:
并发两种方式:sync.WaitGroup,该方法最大优点是Wait()可以阻塞到队列中的所有任务都执行完才解除阻塞,但是它的缺点是不能够指定并发协程数量.
channel优点:能够利用带缓存的channel指定并发协程goroutine,比较灵活.但是它的缺点是如果使用不当容易造成死锁;并且他还需要自己判定并发goroutine是否执行完.
但是相对而言,channel更加灵活,使用更加方便,同时通过超时处理机制可以很好的避免channel造成的程序死锁,因此利用channel实现程序并发,更加方便,更加易用.
**3**.简述go中实现非阻塞IO的原理,以及对goroutine的理解
**4**.如何理解go中的闭包和逃逸分析
```go
func f(i int) func() int {
return func() int {
i++
return i
}
}```
返回的函数就是闭包。
**逃逸分析**:在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法,可以分析在程序的哪些地方可以访问到指针。它涉及到指针分析和形状分析。 当一个变量(或对象)在子程序中被分配时,一个指向变量的指针可能逃逸到其它执行线程中,或者去调用子程序。如果使用尾递归优化(通常在函数编程语言中是需要的),对象也可能逃逸到被调用的子程序中。 如果一个子程序分配一个对象并返回一个该对象的指针,该对象可能在程序中的任何一个地方被访问到——这样指针就成功“逃逸”了。如果指针存储在全局变量或者其它数据结构中,它们也可能发生逃逸,这种情况是当前程序中的指针逃逸。 逃逸分析需要确定指针所有可以存储的地方,保证指针的生命周期只在当前进程或线程中。
**逃逸分析的用处**:最大的好处应该是减少gc的压力,不逃逸的对象分配在栈上,当函数返回时就回收了资源,不需要gc标记清除。
因为逃逸分析完后可以确定哪些变量可以分配在栈上,栈的分配比堆快,性能好
同步消除,如果你定义的对象的方法上有同步锁,但在运行时,却只有一个线程在访问,此时逃逸分析后的机器码,会去掉同步锁运行。
**5**.列出目前OS涉及到的几种进程调度算法,并简述对他们的理解
**6**.假如一个web服务器存在大量的CLOSE_WAIT和LAST_ACK状态的连接,你认为一般是那些原因造成的
**7**.任意演示一段代码,说明golang是如何实现接口的,并能体现他相对oop中继承方式的一些优势
有疑问加站长微信联系(非本文作者))