面试别人笑嘻嘻 自己面试MMP

82 阅读4分钟

面试复盘

今天面试问以前的游戏项目比较多 微服务 分布式这些基本上没问 问了几个golang的基础 和mysql redis 自认为答得一般 没想到还到二面了

string会不会有并发问题 一个协程修改 协程读取 会不会出现问题 频繁修改字符串会有什么问题

  • 可能会出现问题 因为string类型的底层是一个结构体 包含指针和长度字段指针指向固定的字符串数组 这个字符串数组是不可修改的 但是在赋值的时候 需要赋值长度和指针两个值 这个操作显然不是并发安全的 会出现指针修改了 长度未修改的情况 或者指针未修改 长度修改了 这样得到的结果就是错误的 如果修改的len是一样的 那么不会出现问题(个人测试的结果)
  • 会造成大量内存开销和回收压力 修改一个string类型变量的本质是创建一个新的字符串数组 原有字符串数组就会等待回收

map赋值为nil 或者 只定义不初始化 能读操作吗 读到的是什么

  • 这个简单了 就是读到的值是默认零值

for里面修改map 增加或者删除 能看到增加的map内容吗

  • golang的for实现根据类型不同
  1. slice array

     The loop we generate:
       for_temp := range
       len_temp := len(for_temp)
       for index_temp = 0; index_temp < len_temp; index_temp++ {
               value_temp = for_temp[index_temp]
               index = index_temp
               value = value_temp
               original body
       }
    

    循环次数已经确定 新增元素并不影响 遍历的数组也是copy出来的 所以修改并不会影响数据

  2. map

     // The loop we generate:
     //   var hiter map_iteration_struct
     //   for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
     //           index_temp = *hiter.key
     //           value_temp = *hiter.val
     //           index = index_temp
     //           value = value_temp
     //           original body
     //   }
    

    map底层使用hash表实现,插入数据位置是随机的,所以遍历过程中新插入的数据不能保证遍历到,新插入的数据可能刚好插入到已经遍历过的key之前 就访问不到了 删除也是同理 如果在遍历到这个元素之前删除了 那么就读不到 如果在这之后删除了 那么也是能读到的

  3. channel

     // The loop we generate:
     //   for {
     //           index_temp, ok_temp = <-range
     //           if !ok_temp {
     //                   break
     //           }
     //           index = index_temp
     //           original body
     //   }
    

channel中没有元素,则会阻塞等待,如果channel已被关闭,则会解除阻塞并退出循环。

channel赋值为nil 能读到数据吗 一个已经关闭的channel 能读到数据吗 如果能读到 数据读完之后会返回什么

  • channel未初始化或者为nil的时候不能读数据 会阻塞 其实这里和map类似 是能操作 但是里面没有任何数据 所以会一直阻塞
  • 已经关闭的channel是可以读操作 但是不能写操作 未读完数据之前 value,success := <-ch,value是从ch取出来的值 而success是true 读完之后 value=0 success=false
  • 向已经关闭的channel写数据会panic 但是向nil的channel写数据则只是会阻塞

通过channel发送一个结构体 结构体本身包含了map和slice字段 在发送之后修改这些字段 在接收方可见这些修改吗

  • 是可以看到这些修改的 因为发送的时候是值拷贝 结构体会被复制一份 引用类型就是复制的一份指针数据 发送方和接收方是指向的同一块数据 我的理解是这种值拷贝是拷贝的slice和map等引用类型的header信息 这个header信息本身是可以被修改的 他是原来的header的副本 但是其中指向数据内存的指针是同一个地址 所以修改都是可见的 header副本修改则是不可见的

redis的zset底层实现是什么数据结构

  • Zset 类型的底层数据结构是由压缩列表或跳表实现的:

  • 如果有序集合的元素个数小于 128 个,并且每个元素的值小于 64 字节时,Redis 会使用压缩列表作为 Zset 类型的底层数据结构;

  • 如果有序集合的元素不满足上面的条件,Redis 会使用跳表作为 Zset 类型的底层数据结构;

在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了

mysql如果主键是一个无序的字段 大量增加或者修改记录的这个字段 会有什么后果

  • 无序的字段 如果经常修改 会导致索引重建 耗费大量的资源

很晚了 睡觉了 后面想到什么再补充吧