go面试题

面试题连接

https://studygolang.com/articles/17796

go变量哪些是引用类型,哪些是值类型

  1. 指针:slice,map,chan,指针,interface
  2. 值类型:int,float,bool,string,array,struct

golang中new和make的区别

  1. make 仅用来分配及初始化类型为 slice、map、chan 的数据。new 可分配任意类型的数据.
  2. new 分配返回的是指针,即类型 *Type。make 返回引用,即 Type.
  3. new 分配的空间被清零, make 分配空间后,会进行初始化.

go 打印 %v %+v %#v 的区别

  1. %v 只输出所有的值
  2. %+v 先输出字段名字,再输出该字段的值
  3. %#v 先输出结构体名字值,再输出结构体(字段名字+字段的值)
package main
import "fmt"

type student struct {
	id   int32
	name string
}

func main() {
	a := &student{id: 1, name: "xiaoming"}

	fmt.Printf("a=%v	\n", a)
	fmt.Printf("a=%+v	\n", a)
	fmt.Printf("a=%#v	\n", a)
}

go struct能不能比较

因为是强类型语言,所以不同类型的结构不能作比较,但是同一类型的实例值是可以比较的,实例不可以比较,因为是指针类型

go defer(for defer),先进后出,后进先出

func b() {
    for i := 0; i < 4; i++ {
        defer fmt.Print(i)
    }
}

select可以用于什么,常用语gorotine的完美退出

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

5、context包的用途

Context通常被译作上下文,它是一个比较抽象的概念,其本质,是存在上下层的传递,上会把内容传递给下。

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

  1. 使用sync.WaitGroup,就是用来等待一组操作完成的.WaitGroup内部实现了一个计数器,用来记录未完成的操作个数.它提供了三个方法,Add()用来添加计数。Done()用来在操作结束时调用,使计数减一。Wait()用来等待所有的操作结束,即计数变为0,该函数会在计数不为0时等待,在计数为0时立即返回。
应用示例:

package main

import (
    "fmt"
    "sync"
)

func main() {

    var wg sync.WaitGroup

    wg.Add(2) // 因为有两个动作,所以增加2个计数
    go func() {
        fmt.Println("Goroutine 1")
        wg.Done() // 操作完成,减少一个计数
    }()

    go func() {
        fmt.Println("Goroutine 2")
        wg.Done() // 操作完成,减少一个计数
    }()

    wg.Wait() // 等待,直到计数为0
}

  1. 利用的channel的阻塞机制
func Count(ch chan int) {
    ch <- 1
    fmt.Println("Counting")
}

func main() {

    chs := make([] chan int, 10)

    for i:=0; i<10; i++ {
        chs[i] = make(chan int)
        go Count(chs[i])
    }

    for _, ch := range(chs) {
        <-ch
    }

}
  1. select让当前主协程永久阻塞
package main

import (
	"runtime"
    "fmt"
)
func DoSomething() {
	for {
		// 做点什么...
		fmt.Println(111)
		runtime.Gosched() // 防止本协程霸占CPU不放
	}
}

func main() {
	go DoSomething()
	go DoSomething()
	select{}
}

什么是channel,为什么它可以做到线程安全?

  1. Channel是Go中的一个核心类型,可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication),Channel也可以理解是一个先进先出的队列,通过管道进行通信。
  2. Golang的Channel,发送一个数据到Channel和从Channel接收一个数据都是原子性的。
  3. Go的设计思想就是, 不要通过共享内存来通信,而是通过通信来共享内存,前者就是传统的加锁,后者就是Channel。
  4. 也就是说,设计Channel的主要目的就是在多任务间传递数据的,本身就是安全的。

协程和线程和进程的区别?

  1. 进程:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

    每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

  2. 线程:线程是进程的一个实体,线程是内核态,而且是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

    线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

  3. 协程:协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

Go的GPM如何调度?

P作为调度者,M作为执行者,G作为需要执行的任务。
M不会自行去找能执行的任务,每个M都需要跟一个P绑定,P维护一个本地的G队列,M优先执行P本地队列中的G.
如果本地队列没有G,则P会从全局队列中或者其他P的本地队列中获取G;
G被创建优先放置在与该M绑定的P的本地队列中,如果本地队列已满,则P会将前半部分与新创建的G送到全局队列中维护,等待其他P从全局队列中获取。

Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量 ?

Golang中Goroutine 可以通过 Channel 进行安全读写共享变量,还可以通过原子性操作进行.

无缓冲Chan的发送和接收是否同步?

ch := make(chan int) 无缓冲的channel由于没有缓冲发送和接收需要同步.
ch := make(chan int, 2) 有缓冲channel不要求发送和接收操作同步.

channel无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读到数据。
channel有缓冲时,当缓冲满时发送阻塞,当缓冲空时接收阻塞。

https://www.golangroadmap.com/interview/books/questions/golang/25.html

posted @ 2021-11-23 07:20  HaimaBlog  阅读(249)  评论(0编辑  收藏  举报