每日go语言面试题四

1.arp表的作用?arp的分组格式?对于主机不存在的apr请求会发生什么?

arp是将ip地址转换成mac地址,arp分组格式包含目的服务器的mac地址,物理层协议等,若对不存在的主机发送arp请求,没有回应。

2.协程切换的时机?

阻塞(io阻塞、channel阻塞、select阻塞)、等待锁、程序调用sleep等

3.Mutex中sema锁是什么?

sema充当信号量:用来唤醒goroutine

4.Mutex的正常模式和饥饿模式?

Mutex分为正常模式和饥饿模式,正常模式是为了减少协程之间切换的开销,饥饿模式是为了防止协程太长时间没有获得锁。正常模式是当新进来的协程在抢夺锁的时候,会进行自旋进行判断,当锁占有者释放锁的时候,直接讲锁的占用交给自旋者,省去了唤醒和切换的开销。当等待队列的协程等待时间超过一个最大值的时候,mutex切换成饥饿模式,新进入的协程就不会自旋,然后是通过先进先出的方式急性获取锁,当队列里面为空或者队列里面获取锁等待的时间小于某一个值的时候,饥饿模式又会切换成正常模式。

5.实现一个跳表(lc原题 困难)

package main

import (
   "fmt"
   "math/rand"
   "sync"
   "time"
)

func main() {
   list := newSkipList()
   fmt.Println(list)
   list.Set("2", "222")
   list.Set("4", "444")
   list.Set("6", "666")
   list.Set("5", "555")
   list.Set("1", "111")
   list.Set("3", "333")
   list.Remove("1")
   list.Set("1", "111")
   list.Remove("1")
   fmt.Println(list.Get("1"))
   fmt.Println(list.Get("2"))
}

type SkipNode struct {
   Key   string
   Value interface{}
   next  []*SkipNode
}

type SkipList struct {
   head   *SkipNode
   lock   *sync.Mutex
   update []*SkipNode
   rand   *rand.Rand
   maxL   int
   skip   int
   level  int
   length int
}

func newSkipList() *SkipList {
   return &SkipList{
      &SkipNode{
         next: make([]*SkipNode, 32),
      },
      &sync.Mutex{},
      make([]*SkipNode, 32),
      rand.New(rand.NewSource(time.Now().Unix())),
      32,
      4,
      0,
      0,
   }
}
func (this *SkipList) getRandomLevel() int {
   i := 1
   for ; i < this.maxL; i++ {
      if this.rand.Int31()%int32(this.skip) != 0 {
         break
      }
   }
   return i
}

func (this *SkipList) Get(key string) interface{} {
   this.lock.Lock()
   defer this.lock.Unlock()
   pre := this.head
   var next *SkipNode
   for i := this.level - 1; i >= 0; i-- {
      next = pre.next[i]
      for next != nil && next.Key < key {
         pre = next
         next = pre.next[i]
      }
   }
   if next != nil && next.Key == key {
      return next.Value
   }
   return nil
}

func (this *SkipList) Set(key string, value interface{}) {
   this.lock.Lock()
   defer this.lock.Unlock()
   pre := this.head
   var next *SkipNode
   for i := this.level - 1; i >= 0; i-- {
      next = pre.next[i]
      for next != nil && next.Key < key {
         pre = next
         next = pre.next[i]
      }
      this.update[i] = pre
   }

   if next != nil && next.Key == key {
      next.Value = value
      return
   }

   level := this.getRandomLevel()
   if level > this.level {
      this.update[this.level] = this.head
      level = this.level + 1
      this.level++
   }
   node := &SkipNode{
      key,
      value,
      make([]*SkipNode, level),
   }
   for i := 0; i < level; i++ {
      node.next[i] = this.update[i].next[i]
      this.update[i].next[i] = node
   }
   this.length++
}

func (this *SkipList) Remove(key string) {
   this.lock.Lock()
   defer this.lock.Unlock()
   pre := this.head
   var next *SkipNode
   for i := this.level - 1; i >= 0; i-- {
      next = pre.next[i]
      for next != nil && next.Key < key {
         pre = next
         next = pre.next[i]
      }
      this.update[i] = pre
   }
   if next == nil || next.Key != key {
      return
   }
   for index, val := range next.next {
      if this.update[index].next[index] == next {
         this.update[index].next[index] = val
         if this.head.next[index] == nil {
            this.level--
         }
         this.update[index] = nil
      }
   }
}

6.写一个unit test跑一下上一题的代码(重点在规范和case设计上)。

package main

import (
   "testing"
)
func TestCase(t *testing.T) {
   list := newSkipList()
   list.Set("1", "111")
   list.Set("2", "222")
   list.Remove("2")
   list.Set("3", "333")
   list.Remove("3")
   list.Set("3", "333")
   list.Remove("3")
   list.Set("4", "444")
   t.Log(list.Get("1"))
   t.Log(list.Get("2"))
   t.Log(list.Get("3"))
   t.Log(list.Get("4"))
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿联爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值