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"))
}