一次面试补充

loop_0 · · 532 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

#### 1 不好意思, 我之前所说关于interface compare 的问题, 我是记错了, 刚刚找到了以前的代码, 之前我所说的使用interface变量进行对比时, 可以帮你做深度内存对比(memcmp),可能是因为这段代码,golang 中的string类型被设计为值类型, 该类型进行比较时, 底层会帮你进行深度的内存比对, 当时不知道怎么想的就留下了那样的印象 ```go str := "loop" str1 := "li loop" str2 := fmt.Sprintf("%s %s", "li", str) i3 := interface{}(str1) i4 := interface{}(str2) fmt.Println(i3 == i4) ``` #### 2 interface在进行比对时首先会进行类型比较, interface{}(int32(1)) == interface{}(int64(1)) 结果为false,如果类型相同在进行类型判断, 有些类型是不能进行比较的, 比如selice, map, 会直接panic, 之前是依赖那个印象进行推论, 跟您回答的所以那几个回答都不对,然后您之前说的那个返回error的问题做了实验确实是那样, 好坑, 作为interface返回之后type域有了值所以就!=nil了 #### 3 不过如果参考slice != nil的用法来看,我们都知道: * slice 类型不支持比较 * slice 其实底层是这样一个结构体(这个也跟您讲的有问题,没记太清除) ```go struct slice{ size_t cap ; // 从data(实际保存元素的buffer的指针, data地址不一定是申请内存块开始的位置)这个地址开始到申请的内存块结束的大小 / sizeof(TYPE) size_t len ; // 保存的元素个数 TYPE *data ; // 实际保存元素的buffer的指针 } ``` * slice == nil 或者 slice != nil 都做了特殊处理其底层都是判断data == null 或者 data != null 而按照这个逻辑interface也应该有个特殊处理,然而没有,好坑 #### 4 谢谢您对我项目的关注 * 之前根您说的锁链表的方法, 是最近萌生出的想法, 没有实际去实现, 不好意思, 我尝试去实现了一下发现会有各种问题, 方法完全不可行,如下代码 ```go func _unlink(target *LinkNode) { //1. 如果此时target的上一个节点正在unlink操作,并且已经获得该锁,那么将等待,等待结束后, target的上一个节点已经被改变,等待的这个锁没有意义 target.prev.mutex.Lock() defer target.prev.mutex.Unlock() if target.prev != target { target.mutex.Lock() defer target.mutex.Unlock() } if target.prev != target.next && target != target.next { target.next.mutex.Lock() defer target.next.mutex.Unlock() } target.prev.next = target.next target.next.prev = target.prev target.prev = target target.next = target } ``` * 关于您之前提到的一个竞态问题,确实是存在的, 想了一些解决方案 ```go //第一种,在进入修改模式后判断自己是否已经被删除,如果被删除则重新将这个CacheNode加入到CachePool func del( cn *cacheNode){ _unlink(cn.prev, cn.next) cn.prev = cn cn.next = cn } func (cpp *Pool)SearchCacheBall(token string)(cacheBall *Ball, exist bool){ cpp.rwm.RLock() defer cpp.rwm.RUnlock() if cacheNode, ok := cpp.hash[token]; ok{ //进入修改模式 cpp.rwm.RUnlock() cpp.rwm.Lock() if cacheNode.next != cacheNode{ first(cpp.lru, cacheNode) }else{ //如果cacheNode被删除, 那么将其重新加入到CachePool中 if len(cpp.hash) >= cpp.maxSize{ //如果CachePool已经满了,则删除池中最不常用的cacheNode delete(cpp.hash, cpp.lru.prev.token) del(cpp.lru.prev) } cpp.hash[cacheNode.token] = cacheNode push(cpp.lru, cacheNode) } //推出修改模式 cpp.rwm.Unlock() cpp.rwm.RLock() exist = true cacheBall = cacheNode.core } return } ``` ```go //第二种直接改为互斥锁, 将读取map的操作加到互斥的代码块中 type Pool struct{ //同步锁 mx sync.Mutex //用于lru算法, 双向循环链表 lru *cacheNode //用于根据token找到对应cacheNode, hash表 hash map[string]*cacheNode //cachePool的最大容量 maxSize int } func (cpp *Pool)SearchCacheBall(token string)(cacheBall *Ball, exist bool){ cpp.mx.Lock() defer cpp.mx.Unlock() if cacheNode, ok := cpp.hash[token]; ok{ first(cpp.lru, cacheNode) exist = true cacheBall = cacheNode.core } return } func (cpp *Pool)AppendCacheBall(token string, cacheBall *Ball){ cpp.mx.Lock() defer cpp.mx.Unlock() if len(cpp.hash) >= cpp.maxSize{ //如果CachePool已经满了,则删除池中最不常用的cacheNode delete(cpp.hash, cpp.lru.prev.token) del(cpp.lru.prev) } cacheNode := &cacheNode{ token: token, core: cacheBall, } cpp.hash[token] = cacheNode push(cpp.lru, cacheNode) } ```

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

532 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传