Go语言 面试 针对初级、应届、实习

  • 目录

自我介绍、项目介绍、学到的东西

GO相关问题

网络理论

操作系统

数据库

redis


自我介绍、项目介绍、学到的东西

自己写好一段话自我介绍,让人短时间了解你的信息
项目经历要理清思路

GO相关问题

  • 什么是协程(Goroutine)
    协程是用户态轻量级线程,它是线程调度的基本单位。通常在函数前加上go关键字就能实现并发
    。一个Goroutine会以一个很小的栈启动2KB或4KB,当遇到栈空间不足时,栈会自动伸缩, 
    因此可以轻易实现成千上万个goroutine同时启动。

  • new和make的区别?
    new只用于分配内存,返回一个指向地址的指针。它为每个新类型分配一片内存,初始化为0且返
    回类型*T的内存地址,它相当于&T{}
    
    make只可用于slice,map,channel的初始化,返回的是引用。
    

  • gRPC是什么?
    基于go的远程过程调用。RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架
    负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信
    细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信
    细节和调用过程。

  • 怎样等待所有的协程完成?
    1.channel阻塞
    2.sync.WaitGroup,wg.Add()确定等待几个协程个数 wg.Done()释放
    3.在go func()下一行写上time.Sleep()睡眠一段时间

  • uint能否相减
    uint不能直接相减,结果是负数会变成一个很大的uint,这点对动态语言出身的会可能坑。

  • 数组和切片的区别
    Go 切片:又称动态数组,它实际是基于数组类型做的一层封装。
    Go 数组:数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过
    从 0 开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。当作
    为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一
    部分,通过内置函数 len(array)获取其长度。

  • 对map中的key进行排序
    1 golang中没有一个专门的方法针对 map 的 key 进行排序。
    
    2 golang中的 map 默认是无序的,注意也不是按照添加的顺序存放的,每次遍历,得到的
    输出可能不一样。
    
    3 golang中 map 的排序,是先将 key 进行排序,然后根据 key 值遍历输出即可。
    
    简单说就是定一个数组,range map遍历将其append至数组中,然后用sort()方法排序数
    组,遍历数组就能拿到排序过的map,map[k])

  • go的反射
    反射是指在程序运行期对程序本身进行访问和修改的能力。
    支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合
    到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息
    ,并且有能力修改它们。
    
    Go语言提供了 reflect 包来访问程序的反射信息。它定义了两个重要的类型 Type 和 Value 
    任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成,并且 
    reflect 包提供了 reflect.TypeOf 和 reflect.ValueOf 两个函数来获取任意对象的 
    Value 和 Type。

  • 结构体能否比较
    一、是否可以比较
    
    两个结构体比较的前提就是要两个结构体能比较,下面就列举所有不能比较的情况,除了下面的情况,其他的都能比较(比较方法为 == 比较和reflect.DeepEqual 比较)
    
    1.不同结构体之间不能比较(指针除外)
    
    2.同一结构体中如果有map,slice,func 这三种类型的任意一种成员变量都不能用 == 比较(可以用reflect.DeepEqual 比较,因为slice和map不止是需要比较值,还需要比较len和cap,层级比较深的话还需要递归比较,不是简单的==就可以比较的,具体的我们可以参照reflect.DeepEqual()中实现的切片对比代码。 另外有大佬也说会出现循环引用的问题。)
    
    二、比较是否相等
    
    如果两个结构体之间可以比较,那么下面的情况下才会为true,其他的都是false
    
    1.如果是 == 比较必须地址和值都相等才会为true(注:如果有指针类型,那比较的是指针地址)
    
    2.如果两个结构体是同一个结构体初始化来的或者强转来的(保证类型相同),这时如果对应两个结构体间各个成员变量的值都相等,用reflect.DeepEqual比较会为true

  • go的调度模型
    GMP 模型中的 G 全称为 Goroutine 协程,M 全称为 Machine 内核级线程(真正在CPU上跑的),P 全称为 Processor 调度器。对比 GM 模型, GMP 模型新增了本地队列 P。
    GPM 三者相互依赖,G 需要在 M 上才能运行,M 依赖 P 提供资源,P 持有待运行的 G
    M 会从与之绑定的 P 本地队列获取可运行的 G,也会从 全局队列获取可运行的 G,还会从其他 P 偷取 G
    
    ps:go在用GMP之前是GM模型,性能表现相对较差,因为没有P来调度,M获取全局队列中的G是需要锁操作,切换M执行G时会导致线程上下文切换
    总结就是:减少大量的全局队列锁竞争、提高资源利用率(尽量在同1个M中创建和执行 G、偷一半其它本地队列数量的 G、当 M0 执行 G1 的时候被阻塞了,内核系统会调度 M1 重新绑定本地队列 P,然后继续执行 G2)

  • go的逃逸分析?
    检查变量的生命周期是否是完全可知的,如果通过检查,则可以在栈上分配。否则,就是所谓的逃逸,必须在堆上进行分配
    
    go build -gcflags(这个参数) 进行逃逸分析
    
    理解逃逸分析一定能帮助我们写出更好的程序。知道变量分配在栈堆之上的差别,那么我们就要尽量写出分配在栈上的代码,堆上的变量变少了,可以减轻内存分配的开销,减小gc的压力,提高程序的运行速度。

  • goroutine的锁机制?
    go中主要有互斥锁(Mutex)与读写锁(RWMutex)
    互斥锁:是同一时刻某一资源只能上一个锁,此锁具有排他性,上锁后只能被此线程使用,直至解锁。加锁后即不能读也不能写
    读写锁:将使用者分为读者和写者两个概念,支持同时多个读者一起读共享资源,但写时只能有一个,并且在写时不可以读

  • 互斥锁有哪几种模式?
    mutex有两种模式:normal 和 starvation
    
    正常模式
    
    所有goroutine按照FIFO的顺序进行锁获取,被唤醒的goroutine和新请求锁的goroutine同时进行锁获取,通常新请求锁的goroutine更容易获取锁(持续占有cpu),被唤醒的goroutine则不容易获取到锁。公平性:否。
    
    饥饿模式
    
    所有尝试获取锁的goroutine进行等待排队,新请求锁的goroutine不会进行锁获取(禁用自旋),而是加入队列尾部等待获取锁。公平性:是。

  • 有缓冲的channel与无缓冲的channel区别?

    对于无缓冲区channel:
    
    发送的数据如果没有被接收方接收,那么发送方阻塞;如果一直接收不到发送方的数据,接收方阻塞;
    
    有缓冲的channel:
    
    发送方在缓冲区满的时候阻塞,接收方不阻塞;接收方在缓冲区为空的时候阻塞,发送方不阻塞。

  • 简述 Go 语言GC(垃圾回收)的工作原理

    垃圾回收机制是Go一大特(nan)色(dian)。Go1.3采用标记清除法, Go1.5采用三色标记
    法,Go1.8采用三色标记法+混合写屏障。
    
    标记清除法
    
    分为两个阶段:标记和清除
    
    标记阶段:从根对象出发寻找并标记所有存活的对象。
    
    清除阶段:遍历堆中的对象,回收未标记的对象,并加入空闲链表。
    
    缺点是需要暂停程序STW。
    
    三色标记法:
    
    将对象标记为白色,灰色或黑色。
    
    白色:不确定对象(默认色);黑色:存活对象。灰色:存活对象,子对象待处理。
    
    标记开始时,先将所有对象加入白色集合(需要STW)。首先将根对象标记为灰色,然后将一个对象
    从灰色集合取出,遍历其子对象,放入灰色集合。同时将取出的对象放入黑色集合,直到灰色集合为
    空。最后的白色集合对象就是需要清理的对象。
    
    这种方法有一个缺陷,如果对象的引用被用户修改了,那么之前的标记就无效了。因此Go采用了写屏
    障技术,当对象新增或者更新会将其着色为灰色。
    
    一次完整的GC分为四个阶段:
    
    准备标记(需要STW),开启写屏障。
    开始标记
    标记结束(STW),关闭写屏障
    清理(并发)
    基于插入写屏障和删除写屏障在结束时需要STW来重新扫描栈,带来性能瓶颈。混合写屏障分为以下四步:
    
    GC开始时,将栈上的全部对象标记为黑色(不需要二次扫描,无需STW);
    GC期间,任何栈上创建的新对象均为黑色
    被删除引用的对象标记为灰色
    被添加引用的对象标记为灰色
    总而言之就是确保黑色对象不能引用白色对象,这个改进直接使得GC时间从 2s降低到2us。

网络理论

  • tcp、udp区别?

    TCP与UDP区别总结:
    
    1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
    
    2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
    
    3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
    
    UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
    
    4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
    
    5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
    6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
  • 聊聊三次握手、四次挥手

    简单搞笑理解版:
    三次握手:c:我爱你  s:我也爱你 c:我们在一起吧
    四次挥手:c:分手吧? s:死渣男,等我收拾东西 s:分手吧 c:好
    
    三次握手​​​​​​​原理:
    
    第1次握手:客户端发送一个带有SYN(synchronize)标志的数据包给服务端;
    
    第2次握手:服务端接收成功后,回传一个带有SYN/ACK标志的数据包传递确认信息,表示我收到了;
    
    第3次握手:客户端再回传一个带有ACK标志的数据包,表示我知道了,握手结束。
    
    其中:SYN标志位数置1,表示建立TCP连接;ACK标志表示验证字段。
    
    四次挥手​​​​​​​原理:
    
    第1次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态;
    
    第2次挥手:服务端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务端进入CLOSE_WAIT状态;
    
    第3次挥手:服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态;
    
    第4次挥手:客户端收到FIN后,客户端t进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。
    
    其中:FIN标志位数置1,表示断开TCP连接。

  • time_wait和close_wait原因?
    TIME_WAIT:表示主动关闭,通过优化系统内核参数可容易解决。
    CLOSE_WAIT:表示被动关闭,需要从程序本身出发。
    
    close_wait产生的原因是当某一端发送FIN,本端接收到就进入close_wait状态,直到本端发送FIN。
    所以说time_wait是主动关闭的一方会经历的状态,close_wait是被动关闭一方会经历的状态。
    

  • 了解HTTPS么,完整的一次HTTPS请求是怎样的?
    s本意是指SSL,现实中多为TLS(安全传输层协议)
    HTTPS通信主要包括几个节点,发起请求、验证身份、协商秘钥、加密会话,具体流程如下(此例子只有客户端对服务端的单向验证):
    
      1、客户端向服务端发起建立HTTPS请求。
    
      2、服务器向客户端发送数字证书。
    
      3、客户端验证数字证书,证书验证通过后客户端生成会话密钥(双向验证则此处客户端也会向服务器发送证书)。
    
      4、服务器生成会话密钥(双向验证此处服务端也会对客户端的证书验证)。
    
      5、客户端与服务端开始进行加密会话。
    
    参考:https://blog.csdn.net/m0_46364778/article/details/124884079

操作系统

  • 线程和进程区别?
    1.根本区别:进程是操作系统进行资源分配的最小单元,线程是操作系统进行运算调度的最小单元。
    
    2.从属关系不同:进程中包含了线程,线程属于进程。
    
    3.开销不同:进程的创建、销毁和切换的开销都远大于线程。
    
    4.拥有资源不同:每个进程有自己的内存和资源,一个进程中的线程会共享这些内存和资源。
    
    5.控制和影响能力不同:子进程无法影响父进程,而子线程可以影响父线程,如果主线程发生异常会影响其所在进程和子线程。
    
    6.CPU利用率不同:进程的CPU利用率较低,因为上下文切换开销较大,而线程的CPU的利用率较高,上下文的切换速度快。
    
    7.操纵者不同:进程的操纵者一般是操作系统,线程的操纵者一般是编程人员。
    ————————————————
    版权声明:本文为CSDN博主「一个很酷的女巫_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_48271092/article/details/123649795

  • 进程间通信方式有几种 ?
    进程间通信又叫IPC (InterProcess Communication)是指在不同进程之间传播或交换信息。
    IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket。Socket支持不同主机上的两个进程IPC。

  • 哪种效率最高?为什么共享内存通信效率高?
共享内存,将同一块物理内存一块映射到不同的进程的虚拟地址空间中,实现不同进程间对同一资
源的共享。目前最快的IPC形式,不用从用户态到内核态的频繁切换和拷贝数据,直接从内存中读
取就可以,共享内存是临界资源,所以需要操作时必须要保证原子性。使用信号量或者互斥锁都可以。
  • 分页和分段的区别
分段的是以信息逻辑单位划分内存空间,也就是每个程序的空间,是一个一个逻辑划分的,比如一个函数一个函数的逻辑单元;而分页就是固定大小的空间划分的;

一个程序在整体上被分为多个段,一个段又会占用多个页,且一个段对应的页框在物理内存上是可以离散的,而不必连续。

在启用分段和分页机制的情况下,地址的翻译过程是:逻 辑 地 址 → 虚 拟 地 址 → 物 理 地 址

  • 用户态和内核态的切换耗费时间的原因
    总的来说,就是线程切换或者加锁解锁都是因为需要用户态和内核态的切换,从而导致的开销大。
    应用程序的执行需要依托内核提供的资源,包括CPU、存储、IO等,因此内核提供了一个统一的接口,
    也就是系统调用,一个应用程序从用户态进入到内核态,就需要执行系统调用。
    用户态转化为内核态时,需要执行系统调用,保存现场,也就是保存用户态的寄存器等,
    然后去系统调用,并在内核态执行,最后恢复现场。并且由于内核对于用户的不信任,
    因此内核需要对用户进行一些额外的检查,这就需要耗费更多的工作了。
    ————————————————
    版权声明:本文为CSDN博主「Hanyinh」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_43871678/article/details/106723029

数据库

  • 讲讲对索引的理解?有几种?
    索引是帮助MySQL高效获取数据的数据结构。
    
    按数据结构分类:B+tree索引、Hash索引、Full-text索引。
    按物理存储分类:聚集索引、非聚集索引(也叫二级索引、辅助索引)。
    按字段特性分类:主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)。
    按字段个数分类:单列索引、联合索引(也叫复合索引、组合索引)。
    ————————————————
    版权声明:本文为CSDN博主「小瓦匠学编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/u013635487/article/details/122469255

  • mysql如何解决幻读问题?
    隔离级别:可重复读
    
    快照读 MVCC + 当前读 Next-Lock Key(只在可重复读隔离级别下生效)
    间隙锁:间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻id之间出现空
    隙则会形成一个区间,遵循左开右闭原则。间隙锁之间不会冲突。间隙锁是在可重复读隔离
    级别下才会生效的。
    select xxx for update后,会对(id,+∞)行锁和间隙锁防止新增,虽然解决了幻读问题
    ,但一定程度影响并发性能
    
    
    隔离级别:SERIALIZABLE
    
    在这个隔离级别下,事务在读操作时,先加表级别的共享锁,直到事务结束才释放;事务在写
    操作时,先加表级别的排它锁,直到事务结束才释放。也就是说,串行化锁定了整张表,幻读不存在的

  • 讲讲mysql的事务?
    事务是一个最小的不可在分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务是一个最小的工作单元)
    一致性、持久性、原子性、隔离性
    原子性:事务是一个不可分割的工作单位,要么同时成功,要么同时失败。例:当两个人发起转账业务时,如果A转账发起,而B因为一些原因不能成功接受,事务最终将不会提交,则A和B的请求最终不会成功。
    
    持久性:一旦事务提交,他对数据库的改变就是永久的。注:只要提交了事务,将会对数据库的数据进行永久性刷新。
    
    隔离性:多个事务之间相互隔离的,互不干扰
    
    一致性:事务执行接收之后,数据库完整性不被破坏
    
    注意:只有当前三条性质都满足了,才能保证事务的一致性
    ————————————————
    版权声明:本文为CSDN博主「·~简单就好」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_45830276/article/details/125246751

  • 聊聊innodb和myisam
    1、innodb支持事务,而myisam不支持事务。
    2、innodb支持外键,而myisam不支持外键。
    3、innodb默认表锁,使用索引检索条件时是行锁,而myisam是表锁(每次更新增加删除都会锁住表)。
    4、innodb和myisam的索引都是基于b+树,但他们具体实现不一样,innodb的b+树的叶子节点是存放数据的,myisam的b+树的叶子节点是存放指针的。
    5、innodb是聚簇索引,必须要有主键,一定会基于主键查询,但是辅助索引就会查询两次,myisam是非聚簇索引,索引和数据是分离的,索引里保存的是数据地址的指针,主键索引和辅助索引是分开的。
    6、innodb不存储表的行数,所以select count( * )的时候会全表查询,而myisam会存放表的行数,select count(*)的时候会查的很快。
    
    总结:mysql默认使用innodb,如果要用事务和外键就使用innodb,如果这张表只用来查询,可以用myisam。如果更新删除增加频繁就使用innodb。
    ————————————————
    版权声明:本文为CSDN博主「小问号阿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_41832850/article/details/106063426

  • 聊聊redolog和binlog、undolog
    redo log叫做重做日志,是保证事务持久性的重要机制。当mysql服务器意外崩溃或者宕机后,保证已经提交的事务,确定持久化到磁盘中的一种措施。
    binlog 其实说白了就是记录数据库表结构和表表数据的变更,(比如增删改),它不会记录select,因为select没有变化
    undo log撤销日志,在数据库事务开始之前,MYSQL会去记录更新前的数据到undo log文件中。如果事务回滚或者数据库崩溃时,可以利用undo log日志中记录的日志信息进行回退。同时也可以提供多版本并发控制下的读(MVCC)。
    
    对于Mysql Innodb存储引擎而言,每次修改后,不仅需要记录Redo log还需要记录Binlog,而且这两个操作必须保证同时成功或者同时失败,否则就会造成数据不一致。为此Mysql引入两阶段提交。

redis

  • redis中有些什么数据类型?
    Redis 支持的数据类型:string(字符串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)。

  • 缓存穿透、缓存雪崩是什么?如何解决?
    缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
    缓存穿透解决方案:最简单粗暴的方法如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们就把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟;还可以考虑布隆过滤器
    
    缓存雪崩:极小时间段内,redis中大量的key过期,导致命中率极低,数据库压力激增导致崩溃
    解决方案:不让大量key同时失效、搭建集群

  • 讲讲redis的持久化?
    Redis 的持久化有两种方式,或者说有两种策略:
    RDB(Redis Database):指定的时间间隔能对你的数据进行快照存储。
    AOF(Append Only File):每一个收到的写命令都通过write函数追加到文件中

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TCP全连接扫描和TCP SYN扫描都是用于检测目标主机上开放端口的扫描技术,但它们的工作原理略有不同。 TCP全连接扫描是通过向目标主机的每个端口发送一个完整的TCP连接请求来进行扫描。如果一个端口是开放的,那么目标主机将会响应这个连接请求,建立一个完整的TCP连接。如果一个端口是关闭的,那么目标主机将会响应一个RST(重置)消息,表明连接被拒绝。通过分析这些响应消息,扫描器可以确定哪些端口是开放的。 TCP SYN扫描则是通过向目标主机的每个端口发送一个TCP SYN(同步)消息来进行扫描。如果一个端口是开放的,那么目标主机将会响应一个SYN/ACK(同步/确认)消息,表明端口是开放的。如果一个端口是关闭的,那么目标主机将会响应一个RST消息,表明连接被拒绝。通过分析这些响应消息,扫描器可以确定哪些端口是开放的。 TCP全连接扫描和TCP SYN扫描的主要区别在于,TCP全连接扫描需要建立一个完整的TCP连接来进行扫描,而TCP SYN扫描只需要发送一个TCP SYN消息,不需要建立完整的TCP连接。因此,TCP SYN扫描可以更快地进行扫描,同时也更难被目标主机的防火墙和入侵检测系统检测到。但是,TCP SYN扫描也可能会被一些防火墙和入侵检测系统检测到,并被视为一种攻击行为。因此,在进行渗透测试和攻击时,需要根据实际情况选择合适的扫描技术。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值