-
Contains Not Working In Elasticsearch
elastic search painless script 里面的 contains “不生效”, 还好有 Google
参考资料 https://discuss.elastic.co/t/painless-collection-contains-not-working/178944/2
上面的链接 实在是太慢了, 摘抄一下
Because Elasticsearch treats those numbers as Longs by default, you need to make sure that you pass a Long to the contains method. The following should work:
GET testdatatype_unit_tests/_search { "size": 100, "query": { "script": { "script": { "source": "doc['IntCollection'].values.contains(1L)", "lang": "painless" } } } } -
算法导论7.1-快排描述
7.1.2
当数据 A[p..r] 中的元素均相同时, Partition 返回的 q 是什么. 修改 Partition, 使得数据 A[p..r] 中的元素均相同时, 返回 q=(p+r)/2
返回 r
我想不到好办法, 只能 i,j 分别从两头想向走. 代码如下:
def partiton(nums, p, r): if len(nums) <= 1: return 0 x = nums[r] i, j = p, r-1 while True: if nums[i] > x: nums[i], nums[j] = nums[j], nums[i] j -= 1 else: i += 1 if i > j: break if nums[j] < x: nums[i], nums[j] = nums[j], nums[i] i += 1 else: j -= 1 if i > j: break nums[i], nums[r] = nums[r], nums[i] return i def main(): nums = [2]*6 q = partiton(nums, 0, len(nums)-1) assert q == 3 nums = [2]*7 q = partiton(nums, 0, len(nums)-1) assert q == 3 for i in range(10): nums = [0]*i q = partiton(nums, 0, len(nums)-1) assert q == i//2 nums = list(range(10)) q = partiton(nums, 0, len(nums)-1) assert q == 9 nums = [1, 2, 3, 4, 6, 7, 8, 9, 5] q = partiton(nums, 0, len(nums)-1) assert q == 4 import random for _ in range(100): nums = [] for _ in range(10): nums.append(random.randint(1, 10)) q = partiton(nums, 0, len(nums)-1) assert not nums[:q] or max(nums[:q]) <= nums[q] assert not nums[q+1:] or min(nums[q+1:]) >= nums[q] if __name__ == '__main__': main()7.1.4
反过来写一下
def partiton(nums, p, r): i=p-1 x = nums[r] for j in range(p,r): if nums[j]>x: nums[i+1],nums[j] =nums[j],nums[i+1] i+=1 nums[i+1],nums[r] =nums[r],nums[i+1] return i+1 def main(): import random for _ in range(1000): nums = [] for _ in range(10): nums.append(random.randint(1,10)) q = partiton(nums,0,len(nums)-1) print(nums,q,nums[:q],nums[q+1:],nums[q]) assert not nums[:q] or min(nums[:q]) >= nums[q] assert not nums[q+1:] or max(nums[q+1:]) <= nums[q] if __name__ == '__main__': main() -
如何把一个功能在一行代码里面实现
学习资料
几前年看过酷壳的这两篇文章, 当时以为已经掌握了. 现在又想实践一下的时候, 发现完全不知道怎么写了. 所以温习并记录一下.
-
Golang Reflect Method Performance
reflect_test.go
package main import "testing" type A struct { name string } type SetNamer interface { SetName() } func (a *A) SetName() { a.name = "a" } func getA() *A { return &A{} } func getI() SetNamer { return &A{} } func BenchmarkA(b *testing.B) { a := &A{} b.ResetTimer() for i := 0; i < b.N; i++ { a.SetName() } print(a.name) } func BenchmarkB(b *testing.B) { var s SetNamer = &A{} b.ResetTimer() for i := 0; i < b.N; i++ { s.SetName() } } func BenchmarkC(b *testing.B) { a := getA() b.ResetTimer() for i := 0; i < b.N; i++ { a.SetName() } print(a.name) } func BenchmarkD(b *testing.B) { s := getI() b.ResetTimer() for i := 0; i < b.N; i++ { s.SetName() } }测试结果:
% go test -bench=. -cpu=1 agoos: darwin goarch: amd64 BenchmarkA aaaaa1000000000 0.574 ns/op BenchmarkB 537799974 2.17 ns/op aBenchmarkC aaaaa1000000000 0.571 ns/op BenchmarkD 545279128 2.22 ns/op PASS ok _/private/tmp/1576831712 4.101s同样一个 value a, 或者它的申明类型是 struct A , 调用 a.SetName 速度要快很多
相比这下, 如果申明类型是 interface SetNamer, 调用 s.SetName 速度要慢非常多
-
Git Flow Practice
背景
- 公司 APP 每个月迭代一次, 比如说每个月 15 号, 发布一个新版本
- 当前只有一个分支, 所有代码都合并到这个分支, 比如说都合到 master 分支
- 公司的发布系统, 发布之后可以看到每个版本使用的 branch/tag/commit hash 等(这个后面会提到)
这样会生产一个问题:
15 号发版之后, 开始开发新功能, 合到 master 上面, 这些代码会到下个月15号发到线上.
但同时, HotFix 需要马上发到线上. 如果从 master checkout 一个 hotfix 分支出来改代码, 再合回master. master上面会包括还没有测试过的新功能. 那这个hotfix发布之后可能带来问题.最初讨论后的规划
如何在现有的基础(单分支)上解决这个问题
中间有同学提出目前这样也可以解决上面的问题: 功能开发正常推到 master , 如果有 hotfix, 到发布系统看一下当前的 Commit 或者是 Tag, 拉一个新的分支, fix 之后推上去继续发布.
但会有一些问题:
- 每次要做 hotfix, 还要去发布系统查看当前的 tag 或者是 commit
- 如果两个人同时做 hotfix, 可能后面发布的人同学会把前面那个人的覆盖掉
- 分支混乱, 每次 hotfix 后推一个新的分支上来?
会后讨论结果(实践后又有变化):
决定使用dev 和 master 两个分支
- 日常开发推 dev, 15号之后合到 master , 打上 tag
- 15号之后的 hotfix , 从 master 拉分支出来, fix之后合回master, 同时 cherry-pick 到 dev
- 细节上可能会有问题, 再实践中慢慢摸索
改动
增加relese 分支
代码在真正发布到生产之后, 需要先发布到测试环境测试.
使用 dev 发布并没有问题, 但如果结合持续集成(CI), 就有些问题了.我希望的是, 每次 Merge 之后, 会自动发布, 而不需要我每次到发布系统点点点.
显然不能把 Dev 分支配置成自动发布, 否则在新的开发周期, 会频繁做一些无用的发布.所以需要 release 分支. 发布的时候, 直接从 dev checkout 一份最新代码, 推到远端 release, 自动发布.
15 号发布之后, 就把当前 release 代码合到 master, 并打上 tag
保留 master
如果只是为了回滚, tag 足够了. master 是为了方便的 hotfix. 想像一下没有 master, 每次发布还要查看最新的 tag 是什么, 万一再忘了打 tag 呢?
目前实践
总结一下, 实践下来, 保留 2 个主要分支, dev 和 master, 一直存在, 不能删除. 一个临时分支 release.
以一次新的迭代周期开始为例:
- 新的功能开发推到 dev. hotfix 推到 master, 并更新版本号, 并 cherry-pick 到 dev.
- 10 号了, 开始预发布了(一般是先到测试环境), 每次发布就把 dev 的代码合到 release, 推到远端(我一般在命令行操作), CI 会自动做发布.
- 15 号, 发布到生产. release 代码合到 master, 并打一个 tag. (可以由项目 Owner 或者管理员 手工操作)
- 15 号之后, 回到步骤1
2020-03-30 补充
有人提到使用 release 发布太麻烦了, 应该 dev 也能发布. 现成改成了 dev 也会发布. 运行良好.
参考资料:
-
虚拟一个 Mysql 给 Django 用
我想通过 Model 生成建表的 Sql, 但是一定要有一个可用的 Mysql 才行, 觉得很麻烦. 于是找到了这个项目.
https://pypi.org/project/django-fake-database-backends/
安装:
pip install django-fake-database-backends
配置:
DATABASES = { 'default': { 'ENGINE': 'django_fake_database_backends.backends.mysql', } } -
django 连 Mysql 报2059错误
参考https://blog.csdn.net/xiaoyaosheng19/article/details/82643729
原因: 最新的mysql8.0对用户密码的加密方式为caching_sha2_password, django暂时还不支持这种新增的加密方式。只需要将用户加密方式改为老的加密方式即可。
use mysql; alter user 'root'@'localhost' identified with mysql_native_password by 'yourpassword'; flush privileges; -
8皇后问题
问题是8皇后问题有多少种解法(只需要一个总数, 不需要每一个具体的解决方案)
据说是目前效率最高的代码, 使用位运算操作.
#include<stdio.h> int succ, ans; void sol(int cp, int lp, int rp) { if (cp == succ) { ++ans; return; } int p = succ & (~(cp | lp | rp)); while (p) { int bit = p & (-p); sol(cp | bit, (lp | bit) << 1, (rp | bit) >> 1); p &= (p - 1); } } int totalNQueens(int n){ ans = 0; succ = (1 << n) - 1; sol(0, 0 ,0); return ans; } int main(){ int ans; ans = totalNQueens(4); printf("%d\n", ans); }自己看了很久没看明白, 网上搜索了一下资料后才理解, 其实挺简单的. 不记得资料 URL 了, 也不去再找了, 默默致谢一下.
一步步来, 先不管上面的代码, 不管是不是使用位来操作, 先按一个简单的思路写下伪代码.
sol(depth, pos) { // depth 是当前要处理第几行, pos 是前面已经安放好的位置, 也就是上面 depth-1 行的数据 // 如果 N 排数据都已经安置好了, ans 加1 if depth == N+1 { ans++ } p = 根据 pos 计算当前行可以放的所有位置 while ( p 中还有位置可以尝试 ) { next = 取当前行的下一个位置 sol(depth+1, pos.update(next)) update(p) } }我们如果想使用 BIT 记录数据(包括已经安放的位置, 以及当前行可以尝试的位置等等), 以及使用位运算加速, 需要考虑几个问题:
- 如何表示已经安放的位置
- 如何根据问题 1 计算出当前行可以安放的位置
直接看一下上面的代码是如何解决这些问题的.
它并没有直接使用一个变量记录”已经安放的位置”, 而是使用了三个变量间接实现的, 理解了这三个变量就理解这个代码了.
cp 用来记录”只考虑直上直下的冲突, 前面所有行安放的棋子会导致 depth 这一行哪些位置不能放”, 就是说, 第一行放左数第一个位置, 那么第二行就不能再放左数第一个位置了. 拿”八”皇后举例说明, 第一行棋子放在左数第三个位子, 那在计算第二行的位置时, cp = 0b00100000 . 继续在第二行的左数第一个位置放棋子, 计算第三行的位置时, cp = 0b00100000 0b10000000 = 0b10100000 . 很自然的, cp 的初始值应该是 0b00000000 lp 用来记录”右上-左下这条对角线上的冲突, 前面所有行安放的棋子会导致 depth 这一行哪些位置不能放”, 就是说, 第一行放左数第二个位置, 那么第二行就不能再放左数第一个位置了. 拿”八”皇后举例说明, 第一行棋子放在左数第三个位子, 那在计算第二行的位置时, lp = 0b00100000 0b01000000 = 0b01100000 . rp 和 lp 类似, 只是记录 “左上-右下” 这条对角线.
搞清楚这三个变量, 再回头看一下问题1和2 . 问题1并不是一定要解决的, 因为”记录已经安放的位置”也只是为了解决问题2, 我们使用这三个变量有两个好处, 一是可以快速算出问题2, 二是可以使用位运算快速更新三个变量本身
然后, depth 这个变量并不是必需的, 可以使用 cp 取得一样的效果. cp 里面有多少个1, 就代表处理了几行了.
-
Waitgroup In Golang
下面这段代码是模拟一个工作任务: goroutine里面做任务, 主进程里面等任务完成才退出, 避免一个任务因进行中退出. 实际代码肯定会复杂, 这两种线程可能散落在多个文件中.
package main import "sync" var wg sync.WaitGroup func work() { for { wg.Add(1) // ... work here // time.Sleep(time.Second) wg.Done() } } func main() { go work() defer wg.Wait() }乍一看好像也没问题, 但有小概率 Panic: WaitGroup is reused before previous Wait has returned.
直接google查了好几个文章都没解释为什么, 最后还是看官方文档找到解释. 官方文档好啊, 一定要花时间撸一遍才好.
If a WaitGroup is reused to wait for several independent sets of events, new Add calls must happen after all previous Wait calls have returned.上面代码中的 Wait 并不是原子操作, 可能 Wait 还没有结束的时候, 又再次调用到了 Add 方法, 这时候就会 Panic.
-
defer里面的值何时evaluate
第一个问题
我在写这个的时候只是想记录一下像标题中说的, defer 里面的 parameters 何时 evaluate, 就像下面这一个例子. (后面才发现还有 function value 何时 evaluate 的问题)
例子来自于 https://groups.google.com/forum/#!topic/golang-nuts/c7YUK65Xqgs%5B1-25%5D
package main import ( "fmt" ) func main() { for i := 0; i < 10; i++ { defer func() { fmt.Printf("func(): %v\n", i) }() defer printi(i) defer fmt.Printf("i: %v\t", i) } } func printi(i int) { fmt.Printf("printi(): %v\t", i) }结果是这样的
OUTPUT ====== i: 9 printi(): 9 func(): 10 i: 8 printi(): 8 func(): 10 i: 7 printi(): 7 func(): 10 i: 6 printi(): 6 func(): 10 i: 5 printi(): 5 func(): 10 i: 4 printi(): 4 func(): 10 i: 3 printi(): 3 func(): 10 i: 2 printi(): 2 func(): 10 i: 1 printi(): 1 func(): 10 i: 0 printi(): 0 func(): 10二楼的 emepyc 说的很清楚, 我也不画蛇添足了, 直接复制过来
The key point is that the arguments to the deferred functions are evaluated and copied in the invocation of the defer. So:
defer func() { fmt.Printf("func(): %v\n", i) }()No arguments to func(), so i is not copied and the final value of i is used when the deferred function is executed.
defer printi(i) defer fmt.Printf("i: %v\t", i)In both cases, i is the argument of the deferred function, so its value is copied and used when the deferred function is evaluated.
第二个问题
第二个问题, 在我看完之后, 并看了相关的链接资料, 发现是第一个问题的超集.
先来看一下原问题, https://stackoverflow.com/questions/51360229/the-deferred-calls-arguments-are-evaluated-immediately
这个回答里面也给出了 golang 官方资料关于 defer 的链接, 我之前在 google 搜索
golang defer在第一页居然没有出现这个官方链接 .. https://golang.org/ref/spec#Defer_statements . 官方资料里面言简意赅的解释了 defer 的执行规则, 但是… 如果不能精确理解其中一些术语的话, 会看的很不明白, 比如我..由三句话组成, 分别对应三个执行规则.(我是这么理解的, 不精准)
-
Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.
-
Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller.
-
If a deferred function value evaluates to nil, execution panics when the function is invoked, not when the “defer” statement is executed.
对于第一点, https://stackoverflow.com/questions/51360229/the-deferred-calls-arguments-are-evaluated-immediately 这里有非常好的解释了.
第二点, 在 Defer, Panic, and Recover 中第三个例子有解释
func c() (i int) { defer func() { i++ }() return 1 }像上面这段代码, 是返回2
在 https://golang.org/ref/spec#Defer_statements 也有例子
第三点是说, 如果 deferred function value 返回了nil, 不会马上出错, 而是等到外层函数返回之后调用到defer函数的时候才会panic, 如下:
package main import "fmt" func def(s string) func() { fmt.Println("tier up") fmt.Println(s) return nil } func main() { defer def("defered line")() fmt.Println("main") }执行结果
% go run a.go tier up defered line main panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10528e8] goroutine 1 [running]: main.main() /private/tmp/1577163316/a.go:14 +0xc8 exit status 2 -