更多好用的一键脚本请转 https://github.com/ToyoDAdoubi/doubi
ssr.sh
- 脚本说明: ShadowsocksR 一键安装管理脚本,支持单端口/多端口切换和管理
- 系统支持: CentOS6+ / Debian6+ / Ubuntu14+
- 使用方法: https://doub.io/ss-jc42/
- 项目地址: https://github.com/ToyoDAdoubiBackup/shadowsocksr
. . .
更多好用的一键脚本请转 https://github.com/ToyoDAdoubi/doubi
. . .
脚本会递归目录的子目录1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import moviepy.editor as mp
# vfc = mp.VideoFileClip("binary_tree_preorder_traversal.gif")
# vfc.write_videofile("binary_tree_preorder_traversal.mp4")
# vfc = mp.VideoFileClip(".\\mp/binary_tree_preorder_traversal.gif")
# vfc.write_videofile(".\\mp/binary_tree_preorder_traversal1231.mp4")
import os
def getfilelist(rlist,path, ex_filter):
for dir,folder,file in os.walk(path):
for i in file:
if ex_filter not in i:
continue
t = "%s/%s"%(dir,i)
rlist.append(t)
all_gif_path = []
getfilelist(all_gif_path, ".", ".gif")
print all_gif_path
for _gif_path in all_gif_path:
vfc = mp.VideoFileClip(_gif_path)
vfc.write_videofile(_gif_path.replace(".gif", ".mp4"))
推荐参考本博客总结的 algo_newbie
https://github.com/no5ix/no5ix.github.io/blob/source/source/code/test_algo_practice.py
二叉树递归强化
一个桶里面有白球. 黑球各 100 个,现在按下述的规则取球:
i . 每次从桶里面拿出来两个球;
ii. 如果取出的是两个同色的球,就再放入一个黑球;
iii. 如果取出的是两个异色的球,就再放入一个白球。
问:最后桶里面只剩下一个黑球的概率是多少?
1 ^ 2 ^ 3 ^ 1 ^ 2 ^ 3 ^ 3 = (3 ^ 3 ^ 3) ^ (1 ^ 1) ^ (2 ^ 2) = 3^ 0 ^ 0 = 3
。现有一个随机数生成器可以生成0到4的数,现在要让你用这个随机数生成器生成0到6的随机数,要保证生成的数概率均匀。
1 | def rand4(): |
连续整数求和(leetcode第829题, hard实际有思路就easy),要求时间复杂度小于O(N)
1 | class Solution: |
N % (M+1)
的余数, 此处为 1000 % (8+1) = 1
, 求得此余数Y后, 先拿的人第一次就拿Y个, 然后假如B同学第二次拿X个比如是4个, 不管B拿多少个, A之后都拿 (M+1)-X
个即 (8+1)-4=5
个和B同学拿的4个凑成(8+1)=9
个, 这样就保证了A是最后一个拿完棋子的人有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。
测试样例:
[1,3,5,2,2],5,3
返回:2
1 | class Solution_find_top_k_num(object): |
lc41, hard 缺失的第一个正数(leetcode第41题)
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
提示:你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
参考
我们可以采取这样的思路:就把 11 这个数放到下标为 00 的位置, 22 这个数放到下标为 11 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 11 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。
这个思想就相当于我们自己编写哈希函数,这个哈希函数的规则特别简单,那就是数值为 i 的数映射到下标为 i - 1 的位置。
1 | class Solution_lc41(object): |
什么是 “Cache Aside Pattern”?
答:旁路缓存方案的经验实践,这个实践又分读实践,写实践。
先读 cache,再读 db
如果,cache hit,则直接返回数据
如果,cache miss,则访问 db,并将数据 set 回缓存
(1)先从 cache 中尝试 get 数据,结果 miss 了
(2)再从 db 中读取数据,从库,读写分离
(3)最后把数据 set 回 cache,方便下次读命中
先操作数据库,再淘汰缓存(淘汰缓存,而不是更新缓存)
如上图:
(1)第一步要操作数据库,第二步操作缓存
(2)缓存,采用 delete 淘汰,而不是 set 更新
答:如果更新缓存,在并发写时,可能出现数据不一致。
如上图所示,如果采用 set 缓存。
在 1 和 2 两个并发写发生时,由于无法保证时序,此时不管先操作缓存还是先操作数据库,都可能出现:
(1)请求 1 先操作数据库,请求 2 后操作数据库
(2)请求 2 先 set 了缓存,请求 1 后 set 了缓存
导致,数据库与缓存之间的数据不一致。
所以,Cache Aside Pattern 建议,delete 缓存,而不是 set 缓存。
答:如果先操作缓存,在读写并发时,可能出现数据不一致。
如上图所示,如果先操作缓存。
在 1 和 2 并发读写发生时,由于无法保证时序,可能出现:
(1)写请求淘汰了缓存
(2)写请求操作了数据库(主从同步没有完成)
(3)读请求读了缓存(cache miss)
(4)读请求读了从库(读了一个旧数据)
(5)读请求 set 回缓存(set 了一个旧数据)
(6)数据库主从同步完成
导致,数据库与缓存的数据不一致。
所以,Cache Aside Pattern 建议,先操作数据库,再操作缓存。
答:如果先操作数据库,再淘汰缓存,在原子性被破坏时:
(1)修改数据库成功了
(2)淘汰缓存失败了
导致,数据库与缓存的数据不一致。
个人见解:这里个人觉得可以使用重试的方法,在淘汰缓存的时候,如果失败,则重试一定的次数。如果失败一定次数还不行,那就是其他原因了。比如说 redis 故障、内网出了问题。
关于这个问题,沈老师的解决方案是,使用先操作缓存(delete),再操作数据库。假如删除缓存成功,更新数据库失败了。缓存里没有数据,数据库里是之前的数据,数据没有不一致,对业务无影响。只是下一次读取,会多一次 cache miss。这里我觉得沈老师可能忽略了并发的问题,比如说以下情况:
一个写请求过来,删除了缓存,准备更新数据库(还没更新完成)。
然后一个读请求过来,缓存未命中,从数据库读取旧数据,再次放到缓存中,这时候,数据库更新完成了。此时的情况是,缓存中是旧数据,数据库里面是新数据,同样存在数据不一致的问题。
如图:
答:发生写请求后(不管是先操作 DB,还是先淘汰 Cache),在主从数据库同步完成之前,如果有读请求,都可能发生读 Cache Miss,读从库把旧数据存入缓存的情况。此时怎么办呢?
数据库主从不一致
先回顾下,无缓存时,数据库主从不一致问题。
如上图,发生的场景是,写后立刻读:
(1)主库一个写请求(主从没同步完成)
(2)从库接着一个读请求,读到了旧数据
(3)最后,主从同步完成
导致的结果是:主动同步完成之前,会读取到旧数据。
可以看到,主从不一致的影响时间很短,在主从同步完成后,就会读到新数据。
缓存与数据库不一致
再看,引入缓存后,缓存和数据库不一致问题。
如上图,发生的场景也是,写后立刻读:
(1+2)先一个写请求,淘汰缓存,写数据库
(3+4+5)接着立刻一个读请求,读缓存,cache miss,读从库,写缓存放入数据,以便后续的读能够 cache hit(主从同步没有完成,缓存中放入了旧数据)
(6)最后,主从同步完成
导致的结果是:旧数据放入缓存,即使主从同步完成,后续仍然会从缓存一直读取到旧数据。
可以看到,加入缓存后,导致的不一致影响时间会很长,并且最终也不会达到一致。
可以看到,这里提到的缓存与数据库数据不一致,根本上是由数据库主从不一致引起的。当主库上发生写操作之后,从库 binlog 同步的时间间隔内,读请求,可能导致有旧数据入缓存。
思路:那能不能写操作记录下来,在主从时延的时间段内,读取修改过的数据的话,强制读主,并且更新缓存,这样子缓存内的数据就是最新。在主从时延过后,这部分数据继续读从库,从而继续利用从库提高读取能力。
选择性读主
可以利用一个缓存记录必须读主的数据。
如上图,当写请求发生时:
(1)写主库
(2)将哪个库,哪个表,哪个主键三个信息拼装一个 key 设置到 cache 里,这条记录的超时时间,设置为 “主从同步时延”
PS:key 的格式为 “db:table:PK”,假设主从延时为 1s,这个 key 的 cache 超时时间也为 1s。
如上图,当读请求发生时:
这是要读哪个库,哪个表,哪个主键的数据呢,也将这三个信息拼装一个 key,到 cache 里去查询,如果,
(1)cache 里有这个 key,说明 1s 内刚发生过写请求,数据库主从同步可能还没有完成,此时就应该去主库查询。并且把主库的数据 set 到缓存中,防止下一次 cahce miss。
(2)cache 里没有这个 key,说明最近没有发生过写请求,此时就可以去从库查询
以此,保证读到的一定不是不一致的脏数据。
PS:如果系统可以接收短时间的不一致,建议建议定时更新缓存就可以了。避免系统过于复杂。