Golang 面试题 V

一些杂的内容

go的调度

  • 单线程调度器

  • 多线程调度器

  • 任务窃取调度器

  • 抢占式调度器

  • 非均匀存储访问调度器

  • 调度器

go struct能不能比较

struct能不能比较? 很显然这句话包含了两种情况

    1. 同一个struct的两个实例能不能比较?
    1. 两个不同的struct的实例能不能比较?

同一个struct的两个实例可比较也不可比较,当结构不包含不可直接比较成员变量时可直接比较,否则不可直接比较
两个不同的struct的实例可比较也不可比较, 如果成员变量中含有不可比较成员变量,即使可以强制转换,也不可以比较

可比较与不可比较类型

  • 可比较: Integer, Floating-point, String, Boolean, Complex(复数型), Pointer, Channel, Interface, Array
  • 不可比较: Slice, Map, Function

go defer(for defer)

defer和go一样都是Go语言提供的关键字。defer用于资源的释放,会在函数返回之前进行调用。
如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func f1() (r int) {
defer func() {
r++
}()
return 0
}

func f2() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}

func f3() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}

请读者先不要运行代码,在心里跑一遍结果,然后去验证。

例1的正确答案不是0,例2的正确答案不是10,如果例3的正确答案不是6……

函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。

其实使用defer时,用一个简单的转换规则改写一下,就不会迷糊了。改写规则是将return语句拆成两句写,return xxx会被改写成:

1
2
3
返回值 = xxx
调用defer函数
空的return

答案: 例1: 1 例2: 5 例3: 1

select可以用于什么

select 只能应用于channel 的操作,既可以用于channel 的数据接收,也可以用于channel 的数据发送。 如果select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行。

context包的用途

context 包是Go 1.7 引入的标准库,主要用于在goroutine 之间传递取消信号、超时时间、截止时间以及一些共享的值等。 它并不是太完美,但几乎成了并发控制和超时控制的标准做法。 使用上,先创建一个根节点的context,之后根据库提供的四个函数创建相应功能的子节点context。

client如何实现长连接

net.Dialer.KeepAlive:开启长连接(说明默认http client是默认开启长连接的)

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

  • channel实现同步
  • sync.WaitGroup

slice,len,cap,共享,扩容

1
2
3
4
5
type slice struct {
array unsafe.Pointer
len int
cap int
}

slicelen==cap后,再向slice中追加元素时,会发生扩容

扩容遵循如下规则:(但结果不完全遵循此规则)

  • 如果原slice容量小于1024,则新slice容量将扩大为原来的2倍;
  • 如果原slice容量大于等于1024,则新slice容量将扩大为原来的1.25倍;
  • 如果扩容后的大小仍不能满足,那么直接扩容到所需的容量
  • 在以上计算完新slice容量后,交由管理内存的组件申请内存,按照给出的表向上取整进行内存申请,申请出来的内存长度,作为slice扩容后的容量

map如何顺序读取

由于map底层实现与 slice不同, map底层使用hash表实现,插入数据位置是随机的, 所以遍历过程中新插入的数据不能保证遍历。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
"sort"
)

func main() {
m := make(map[string]string)
m["b"] = "2"
m["a"] = "1"
m["c"] = "3"

keys := make([]string, 0, len(m))
for k, _ := range m {
keys = append(keys, k)
}

sort.Strings(keys)

for _, k := range keys {
fmt.Printf("Key:%+v, Value:%+v\n", k, m[k])
}
}

对 key 排序,那么我们便可将 map 的 key 全部拿出来,放到一个数组中,然后对这个数组排序后对有序数组遍历,再间接取 map 里的值就行了。

大文件排序

  • 随机数
  • 类型转换
  • 文件操作
  • priorityqueue优先级队列

基本排序,哪些是稳定的

  • 常见的7种排序算法

    • 选择排序
    • 冒泡排序
    • 插入排序
    • 希尔排序
    • 归并排序
    • 快速排序
    • 堆排序
  • 稳定的排序算法

    • 冒泡排序
    • 插入排序
    • 归并排序

http get跟head

HTTP协议中GET、POST和HEAD的区别? HEAD: 只请求页面的首部。 GET: 请求指定的页面信息,并返回实体主体。 POST: 请求服务器接受所指定的文档作为对所标识的URL.

http keep-alive

当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接

http能不能一次连接多次请求,不等后端返回

如果是http1.0,一个tcp连接只能发一个http请求,如果是http1.1及以上,引入了持续连接的概念,所以一个tcp连接能发多个http请求。

linux命令,查看端口占用,cpu负载,内存占用,如何发送信号给一个进程

  • 查看端口占用
1
2
3
4
5
// lsof
lsof -i:端口号

// netstat
netstat -tunlp | grep 端口号
  • 查看cpu负载
1
2
3
4
5
6
7
8
9
top

vmstat 1 5

sar -u 1 5

iostat -c 1 2

dstat -c
  • 查看内存占用
1
2
3
4
5
6
7
8
9
df -m

free

cat /proc/meminfo

ps aux -sort -rss

vmstat -s

git文件版本,使用顺序,merge跟rebase

  • 使用 rebase 和 merge 的基本原则:
    • 下游分支更新上游分支内容的时候使用 rebase
    • 上游分支合并下游分支内容的时候使用 merge
    • 更新当前分支的内容时一定要使用 --rebase 参数

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :