Go语言基础面试题

一、选择题
1.关于异常设计,下面说法正确的是()

A. 在程序开发阶段,坚持速错,让程序异常崩溃 // 开发--测试--准生产--生产
B. 在程序部署后,应恢复异常避免程序终止
C. 一切皆错误,不用进行异常设计
D. 对于不应该出现的分支,使用异常处理

参考答案:ABD

2.关于异常的触发,下面说法正确的是()

A. 空指针解析
B. 下标越界
C. 除数为0
D. 调用panic函数

参考答案:ABCD

3.关于函数返回值的错误设计,下面说法正确的是()

A. 如果失败原因只有一个,则返回bool
B. 如果失败原因超过一个,则返回error
C. 如果没有失败原因,则不返回bool或error
D. 如果重试几次可以避免失败,则不要立即返回bool或error

参考答案:ABCD

4.下面关于recover使用正确的是?

A.recover()
B.defer recover()
C.defer func() {
recover()
}()
D. defer func() {
defer func() {
recover()
}()
}()


答案:C。recover() 必须在 defer() 函数中直接调用才有效。,不能嵌套使用,不能直接使用

5.函数执行时,如果由于 panic 导致了异常,则延迟函数不会执行。这一说法是否正确?

A. 正确
B. 错误
参考答案及解析:B。 defer结合recover可以修复panic
6.错误是业务过程的一部分,而异常不是,这句话是否正确()

A.正确

B.错误

答案:A。异常是要避免的

二、简答题
1.写出下面代码的输出

package main

import "fmt"

func main() {
defer_all()
panic("触发异常")
}

func defer_all() {
defer func() {
fmt.Println("打印前")
}()
defer func() {
fmt.Println("打印中")
}()
defer func() {
fmt.Println("打印后")
}()
}

这道题主要考察的是对 defer 的理解,defer 主要是延迟函数,延迟到调用者函数执行 return 命令之前

2.写出下面代码的执行结果

package main

import (
"fmt"
)

func main() {
defer_call()
}

func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}

打印后
打印中
打印前
panic: 触发异常


参考解析:defer 的执行顺序是先进后出,后进先出
当出现 panic 语句的时候,会先按照 defer 的后进先出的顺序执行,最后才会执行panic

3.下面代码的执行结果为?

package main

import "fmt"

func main() {
a := 1
b := 2
defer Sum( a, b)
a = 3
defer Sum( a, b)
b = 4
}

func Sum(a, b int) {
ret := a + b
fmt.Println(a, b, ret)
}



答案:defer先进后出,后进先出

4.下面代码能正常编译吗?

package main

import "fmt"

func main() {
nil := 1
var map_data map[string]int = nil
fmt.Println(map_data)
}


答案:不能,此时的nil是int类型的变量

一、选择题
1.关于协程,下面说法正确是?

A. 协程和线程都可以实现程序的并发执行
B. 线程比协程更轻量级
C. 协程不存在死锁问题
D. 通过channel来进行协程间的通信

参考答案:AD

2.关于channel,下面语法正确的是()

A. var ch chan int
B. ch := make(chan int)
C. <- ch
D. ch <-



参考答案:ABC


D答案少了写入的数据:ch <- 3

3.关于同步锁,下面说法正确的是()

A. 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
B. RWMutex在读锁占用的情况下,会阻止写,但不阻止读
C. RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占
D. Lock()操作需要保证有Unlock()或RUnlock()调用与之对应

参考答案:ABC。Lock对应Unlock,RLock对应RUnlock

读写锁:
写锁:写写互斥,写读互斥
读锁:读读不互斥,读写互斥

4.关于channel的特性,下面说法正确的是()

A. 给一个 nil channel 发送数据,造成永远阻塞
B. 从一个 nil channel 接收数据,造成永远阻塞
C. 给一个已经关闭的 channel 发送数据,引起 panic
D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值

参考答案:ABCD

5.关于 channel 下面描述正确的是?

A. 向已关闭的通道发送数据会引发 panic;

B. 从已关闭的缓冲通道接收数据,返回已缓冲数据或者零值;

C. 无论接收还是发送,nil 通道都会阻塞;

参考答案及解析:ABC。

6.关于无缓冲和有冲突的channel,下面说法正确的是()

A. 无缓冲的channel是默认的缓冲为1的channel // 默认位0
B. 无缓冲的channel和有缓冲的channel都是同步的
C. 无缓冲的channel和有缓冲的channel都是非同步的
D. 无缓冲的channel是同步的,而有缓冲的channel是非同步的

参考答案:D。

7.关于select机制,下面说法正确的是()

A. select机制用来处理异步IO问题
B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
C. golang在语言级别支持select关键字
D. select关键字的用法与switch语句非常类似,后面要带判断条件

参考答案:ABC

8下面代码输出什么?请简要说明。

type MyMutex struct {
count int
sync.Mutex
}

func main() {
var mu MyMutex
mu.Lock()
var mu1 = mu
mu.count++
mu.Unlock()
mu1.Lock()
mu1.count++
mu1.Unlock()
fmt.Println(mu.count, mu1.count)
}
A. 不能编译;
B. 输出 1, 1;
C. 输出 1, 2;
D. fatal error;
参考答案及解析:D。加锁后复制变量,会将锁的状态也复制,所以 mu1 其实是已经加锁状态,再加锁会死锁。

代码优化后的:

func main() {
var mu MyMutex
mu.Lock()
mu.count++
mu.Unlock()
var mu1 = mu
mu1.Lock()
mu1.count++
mu1.Unlock()
fmt.Println(mu.count, mu1.count)
}

二、简答题
1.select是随机的还是顺序的?

随机的

2.协程,线程,进程的区别?

进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元;

同一个进程中可以包括多个线程;

进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束;

线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程;


线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源;

进程是资源分配的单位

线程是操作系统调度的单位

进程切换需要的资源很最大,效率很低 线程切换需要的资源一般,效率一般 协程切换任务资源很小,效率高 多进程、多线程根据cpu核数不一样可能是并行的 也可能是并发的。协程的本质就是使用当前进程在不同的函数代码中切换执行,可以理解为并行。 协程是一个用户层面的概念,不同协程的模型实现可能是单线程,也可能是多线程。

进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。(全局变量保存在堆中,局部变量及函数保存在栈中)

线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是这样的)。

协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。

一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。

协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

3.说说go语言中的协程?

协程和线程都可以实现程序的并发执行;

通过channel来进行协程间的通信;

只需要在函数调用前添加go关键字即可实现go的协程,创建并发任务;

关键字go并非执行并发任务,而是创建一个并发任务单元;

4.说说go语言的channel特性?

给一个 nil channel 发送数据,造成永远阻塞

从一个 nil channel 接收数据,造成永远阻塞

给一个已经关闭的 channel 发送数据,引起 panic

从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值

无缓冲的channel是同步的,而有缓冲的channel是非同步的

5.说说go语言的select机制?

A. select机制用来处理异步IO问题

B. select机制最大的一条限制就是每个case语句里必须是一个IO操作

C. golang在语言级别支持select关键字

6.select可以用于什么?

常用于gorotine的完美退出
golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作
每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作

7.主协程如何等其余协程完再操作

sync.WiteGroup

Add() 指定计数器
Done() 计数器减1
Wite() 等待计数器减为0,结束

8.sync.Once的作用?实现一个单例

sync.Once 是 Golang package 中使方法只执行一次的对象实现,作用与 init 函数类似。但也有所不同。

init 函数是在文件包首次被加载的时候执行,且只执行一次
sync.Onc 是在代码运行中需要的时候执行,且只执行一次
当一个函数不希望程序在一开始的时候就被执行的时候,我们可以使用 sync.Once 。

9.死锁条件,如何避免?

死锁产生的原因
1.系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁
2.请求和释放资源的顺序不当,会导致死锁
如何避免:
channel推送和读取同时存在时才不会发生死锁,而且需要注意channel读写的顺序,只读或只推都会发生死锁
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值