22

ARTS 第13周

 5 years ago
source link: https://www.tuicool.com/articles/by2ueuI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK