• 协程的原理和上层调用机制

  • 二分查找拐点的一个问题

    题目: 一个先升序再降序的数组, 二分查找拐点位置

    方法2跑了更多的分支, 但是时间却比较短. 为什么呢?

  • Kotlin Lombok Data

    刚刚发现一个 Kotlin 文件不能访问 lombok.Data 里面的private属性, 而另外一个可以.

    之前遇到过类似的问题, 所以原因我也一下就想到了~ :) 但是到网上搜索了一下解决方法, 却发现解决不了哈哈. 记录一下.

    之前遇到的问题好像是这样的, 一个 Java 方法没办法访问 Kotlin Data Class 里面的属性. 解决方法 G 了一下就找到了, 在官网也有说明, 是编译顺序的问题, 需要先编译 Kotlin 再 Java

    那这次遇到的问题, 恰恰反了过来, 需要先编译 Java, 那就没得搞了.

    前面说一个Kt 能访问 lombok.Data class, 另外一个不能, 是因为他们不在一个 Module

  • 一起来打牌

  • {{ totalScore(person) }} {{ person.name }} {{ score }}
  • Graphql Java

    写在最前

    我不是写一个 GraphQL 的使用指南, 是在写自己对 GraphQL 的一些使用感受. 我自己是非常喜欢它, 愿意给他打10分, 虽然还有些小瑕疵. 如果你用过 GraphQL 了, 可以看看我们是不是有同感.

    另外多提两句. 1 GraphQL 本身是一个协议, 每种语言都有自己的框架实现, 我自己只用过 Java 的. 2 他是一个执行引擎, 不是 HTTP 框架, 你可以在任何地方使用他们, 当然现在最常见的是提供 HTTP 接口.

  • 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

    背景

    1. 公司 APP 每个月迭代一次, 比如说每个月 15 号, 发布一个新版本
    2. 当前只有一个分支, 所有代码都合并到这个分支, 比如说都合到 master 分支
    3. 公司的发布系统, 发布之后可以看到每个版本使用的 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 两个分支

    1. 日常开发推 dev, 15号之后合到 master , 打上 tag
    2. 15号之后的 hotfix , 从 master 拉分支出来, fix之后合回master, 同时 cherry-pick 到 dev
    3. 细节上可能会有问题, 再实践中慢慢摸索

    改动

    增加relese 分支

    代码在真正发布到生产之后, 需要先发布到测试环境测试.
    使用 dev 发布并没有问题, 但如果结合持续集成(CI), 就有些问题了.

    我希望的是, 每次 Merge 之后, 会自动发布, 而不需要我每次到发布系统点点点.
    显然不能把 Dev 分支配置成自动发布, 否则在新的开发周期, 会频繁做一些无用的发布.

    所以需要 release 分支. 发布的时候, 直接从 dev checkout 一份最新代码, 推到远端 release, 自动发布.

    15 号发布之后, 就把当前 release 代码合到 master, 并打上 tag

    保留 master

    如果只是为了回滚, tag 足够了. master 是为了方便的 hotfix. 想像一下没有 master, 每次发布还要查看最新的 tag 是什么, 万一再忘了打 tag 呢?

    目前实践

    总结一下, 实践下来, 保留 2 个主要分支, dev 和 master, 一直存在, 不能删除. 一个临时分支 release.

    以一次新的迭代周期开始为例:

    1. 新的功能开发推到 dev. hotfix 推到 master, 并更新版本号, 并 cherry-pick 到 dev.
    2. 10 号了, 开始预发布了(一般是先到测试环境), 每次发布就把 dev 的代码合到 release, 推到远端(我一般在命令行操作), CI 会自动做发布.
    3. 15 号, 发布到生产. release 代码合到 master, 并打一个 tag. (可以由项目 Owner 或者管理员 手工操作)
    4. 15 号之后, 回到步骤1

    2020-03-30 补充

    有人提到使用 release 发布太麻烦了, 应该 dev 也能发布. 现成改成了 dev 也会发布. 运行良好.

    参考资料: