ARTS 第13周

ARTS 第13周分享

[TOC]

Algorithm

双链表的实现

难度:[easy]

[参考代码]

type heroNode2 struct {
    No       int
    Name     string
    NickName string
    front    *heroNode2
    next     *heroNode2
}
type DoubleLinkList struct {
    head *heroNode2
}

func NewHero2(no int, name, nickName string) *heroNode2 {
    return &heroNode2{No: no, Name: name, NickName: nickName}
}

func NewDoubleLink() DoubleLinkList {
    return DoubleLinkList{NewHero2(0, "", "")}
}

func (d *DoubleLinkList) add(hero *heroNode2) {
    tmp := d.head
    for tmp.next != nil {
        tmp = tmp.next
    }
    hero.front = tmp
    tmp.next = hero
}

func (d *DoubleLinkList) addOrder(hero *heroNode2) {
    tmp := d.head
    flag := false
    for {
        if tmp.No == hero.No {
            fmt.Println("have this Node...")
            return
        } else if tmp.No > hero.No {
            flag = true
            break
        }
        if tmp.next == nil {
            break
        }
        tmp = tmp.next
    }
    if flag {
        tmp.front.next = hero
        hero.front = tmp.front
        tmp.front = hero
        hero.next = tmp
    } else {
        tmp.next = hero
        hero.front = tmp
    }
}

func (d *DoubleLinkList) list() {
    if d.head.next == nil {
        fmt.Println("empty double list")
        return
    }

    tmp := d.head.next
    for tmp != nil {
        fmt.Printf("No: %d\tName: %s\tNickName: %s\n", tmp.No, tmp.Name, tmp.NickName)
        tmp = tmp.next
    }
}

func (d *DoubleLinkList) delete(hero *heroNode2) {
    if d.head.next == nil {
        fmt.Println("empty double list")
        return
    }
    tmp := d.head.next
    flag := false
    for tmp != nil {
        if tmp.No == hero.No {
            flag = true
            break
        }
    }
    if flag {
        tmp.front.next = tmp.next
        if tmp.next != nil {
            tmp.next.front = tmp.front
        }
    } else {
        fmt.Println("doesn't have this hero...")
    }
}

func (d *DoubleLinkList) update(hero *heroNode2) {
    if d.head.next == nil {
        fmt.Println("empty double list")
        return
    }
    tmp := d.head.next
    for tmp != nil {
        if tmp.No == hero.No {
            tmp.Name = hero.Name
            tmp.NickName = hero.NickName
            break
        }
        tmp = tmp.next
    }
}

func (d *DoubleLinkList) count() int {
    count := 0
    tmp := d.head
    for tmp.next != nil {
        count++
        tmp = tmp.next
    }
    return count
}

func (d *DoubleLinkList) reverse() {
    if d.head.next == nil || d.head.next.next == nil {
        return
    }
    //遍历这个list,将每一元素取出,插入新list的头结点后面
    pCur := d.head.next
    pNext := pCur.next
    newDouble := NewDoubleLink()
    for {
        fmt.Println(pCur, pNext)

        if newDouble.head.next == nil {
            fmt.Println("first---------")
            newDouble.head.next = pCur
            pCur.front = newDouble.head
            newDouble.list()
            fmt.Println("----------")
            d.list()
        } else {
            pCur.next = newDouble.head.next
            pCur.front = newDouble.head
            newDouble.head.next.front = pCur
            newDouble.head.next = pCur
            newDouble.list()
        }

        pCur = pNext
        if pCur == nil {
            break
        }
        pNext = pNext.next
    }
    d.head = newDouble.head
    log.Fatal()
}

func (d *DoubleLinkList) reIndex(num int) *heroNode2 {
    if d.head.next == nil {
        fmt.Println("empty double linklist")
        return nil
    }
    if d.count()-1 < num {
        fmt.Println("invalid index")
        return nil
    }
    tmp := d.head.next
    for tmp.next != nil {
        tmp = tmp.next
    }
    for i := 0; i < num; i++ {
        tmp = tmp.front
    }
    return tmp
}

func (d *DoubleLinkList) reList() {
    if d.head.next == nil {
        fmt.Println("empty link list")
        return
    }
    tmp := d.head.next
    for tmp.next != nil {
        tmp = tmp.next
    }
    for tmp != d.head {
        fmt.Printf("No: %d\tName: %s\tNickName: %s\n", tmp.No, tmp.Name, tmp.NickName)
        tmp = tmp.front
    }
}

func (d *DoubleLinkList) reList2() {
    d.reverse()
    d.list()
    d.reverse()
}

Review

Error Handling In Go, Part I https://www.ardanlabs.com/blog/2014/10/error-handling-in-go-part-i.html

主要讲golang中的错误处理

Tips

学会聆听,职场最重要的事情 https://mp.weixin.qq.com/s/j0dzIBKJMzXJJh6gm6QJog

https://mp.weixin.qq.com/s/j0dzIBKJMzXJJh6gm6QJog

画外音:帮助下属成长和提升,是leader的核心职责。
第一层聆听:下载式聆听(downloading)

说明:这类聆听,通常会根据自己的经验和习惯做出应激性反应,
它只会听到自己认可的部分,
默认忽略自己经验之外的部分,还对这些部分做主观评判,
这类聆听以自我为中心。
第二层聆听:看到事实(factual listening)

说明:这类聆听,
不仅能听到自己认可的部分,还能听到自己已有认知以外的部分,
这类聆听以事实为中心。
第三层聆听:同理心(empathic listening)

说明:这类聆听,不仅能听到事实,
还能以对方的视角,建立情感连接,
尝试去理解述说者背后的情感与逻辑,以便更好的体会为什么会说这样的话。
这类聆听以倾诉者为中心。
关键词:
对方视角(seeing through another persion's eyes)
情感连接(emotional connection)
画外音:这类聆听,更够更好的理解别人的语言与行为。
第四层聆听:生成性聆听(generative listening)

说明:前三层聆听,看到自己的认知,看到自己认知外的事实,尝试理解对方。第四次聆听,
是以发展的为中心,尝试了解对方的本心(source),
并看到帮ta走向自己本心的方法,扩大彼此认知的方法。

Share

mysql 缓冲池(buffer pool): https://mp.weixin.qq.com/s/nA6UHBh87U774vu4VvGhyw

https://mp.weixin.qq.com/s/nA6UHBh87U774vu4VvGhyw

应用系统分层架构,为了加速数据访问,会把最常访问的数据,放在缓存(cache)里,避免每次都去访问数据库。
缓存表数据与索引数据,把磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用。
缓存访问快,但容量小
内存访问快,但容量小
以“最大限度”的降低磁盘访问
磁盘读写,并不是按需读取,而是按页读取,一次至少读一页数据(一般是4K)
数据访问,通常都遵循“集中读写”的原则,使用一些数据,大概率会使用附近的数据,这就是所谓的“局部性原理”,它表明提前加载是有效的,确实能够减少磁盘IO。
磁盘访问按页读取能够提高性能,所以缓冲池一般也是按页缓存数据;
预读机制启示了我们,能把一些“可能要访问”的页提前加入缓冲池,避免未来的磁盘IO操作;
画外音:为了减少数据移动,LRU一般用链表实现。
由于预读(Read-Ahead),提前把页放入了缓冲池,但最终MySQL并没有从页中读取数据,称为预读失效。
画外音:但也不要因噎废食,因为害怕预读失败而取消预读策略,大部分情况下,局部性原理是成立的,预读是有效的。
当某一个SQL语句,要批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL性能急剧下降,这种情况叫缓冲池污染。
这类like不能命中索引,必须全表扫描,就需要访问大量的页:

1.把页加到缓冲池(插入老生代头部);
2.从页里读出相关的row(插入新生代头部);
如此一来,所有的数据页都会被加载到新生代的头部,但只会访问一次,真正的热数据被大量换出。
MySQL缓冲池加入了一个“老生代停留时间窗口”的机制:
(1)假设T=老生代停留时间窗口;
(2)插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部;
(3)只有满足“被访问”并且“在老生代停留时间”大于T,才会被放入新生代头部;
加入“老生代停留时间窗口”策略后,短时间内被大量加载的页,并不会立刻插入新生代头部,而是优先淘汰那些,短期内仅仅访问了一次的页。
而只有在老生代呆的时间足够久,停留时间大于T,才会被插入新生代头部。
参数:innodb_buffer_pool_size
介绍:配置缓冲池的大小,在内存允许的情况下,DBA往往会建议调大这个参数,越多数据和索引放到内存里,数据库的性能会越好。
参数:innodb_old_blocks_pct
介绍:老生代占整个LRU链长度的比例,默认是37,即整个LRU中新生代与老生代长度比例是63:37。
画外音:如果把这个参数设为100,就退化为普通LRU了。
参数:innodb_old_blocks_time
介绍:老生代停留时间窗口,单位是毫秒,默认是1000,即同时满足“被访问”与“在老生代停留时间超过1秒”两个条件,才会被插入到新生代头部。
总结
(1)缓冲池(buffer pool)是一种常见的降低磁盘访问的机制;
(2)缓冲池通常以页(page)为单位缓存数据;
(3)缓冲池的常见管理算法是LRU,memcache,OS,InnoDB都使用了这种算法;
(4)InnoDB对普通LRU进行了优化:
将缓冲池分为老生代和新生代,入缓冲池的页,优先进入老生代,页被访问,才进入新生代,以解决预读失效的问题
页被访问,且在老生代停留时间超过配置阈值的,才进入新生代,以解决批量数据访问,大量热数据淘汰的问题
思路,比结论重要。

本周阅读

第4周:1, 2, 3, 4, 
缓冲池(buffer pool),这次彻底懂了!!!https://mp.weixin.qq.com/s/nA6UHBh87U774vu4VvGhyw

什么叫CQRS!https://mp.weixin.qq.com/s/-9TS3p7gSvrS3P3vOM81YQ
学会聆听,职场最重要的事情:https://mp.weixin.qq.com/s/j0dzIBKJMzXJJh6gm6QJog
Go 语言中的错误处理 - 第二部分:https://mp.weixin.qq.com/s/nxtEB6q3jophnnnvQaYNDA

Error Handling In Go, Part I: https://www.ardanlabs.com/blog/2014/10/error-handling-in-go-part-i.html
拓扑排序原理与解题套路:https://mp.weixin.qq.com/s/r2Sf0I0JarpXmvBlX_1LTg

Libra:Facebook的"野心"?https://mp.weixin.qq.com/s/4-RqXa0hQ-f77DVj8r3RYg
git 上的pull request 是什么意思?https://www.cnblogs.com/zhaoyanjun/p/5134274.html
什么叫CQRS!https://mp.weixin.qq.com/s/-9TS3p7gSvrS3P3vOM81YQ