DevilKing's blog

冷灯看剑,剑上几分功名?炉香无需计苍生,纵一穿烟逝,万丈云埋,孤阳还照古陵

0%

Git flow可能不适合你

git flow model

Git flow

调整后的git-flow流部分:

  • master分支, 正式发行的tag部分,作为版本库方式
  • develop分支,最新的
  • task分支,feature or issue fix, from develop, 通过后,rebase到最新的develop,再--no-ff的merge回develop,随后这个task就可以砍掉了
  • release分支,from develop部分,如果有修改的话,会merge回develop部分,

随后的一些操作:

  • 针对master部分,进行打tag部分,也就是从release部分,直接复制过去,而不是merge的方式,随后,删除掉release分支

针对现有的android部分的开发流程的问题:

  • 现在master分支实际上是类似于develop分支
  • task分支无,采用pr的方式来进行
  • release分支,实际上类似于现在weekly-xx分支
  • 但是master分支,没有,没有相关的tag部分,无法进行版本的查询

Golang Internals Part 2: Nice benefits of named return values

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type objectInfo struct {
arg1 int64
arg2 uint64
arg3 string
arg4 []int
}
func NoNamedReturnParams(i int) (objectInfo) {

if i == 1 {
// Do one thing
return objectInfo{}
}

if i == 2 {
// Do another thing
return objectInfo{}
}

if i == 3 {
// Do one more thing still
return objectInfo{}
}

// Normal return
return objectInfo{}
}

actual code that the golang compiler generates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"".NoNamedReturnParams t=1 size=243 args=0x40 locals=0x0
0x0000 TEXT "".NoNamedReturnParams(SB), $0-64
0x0000 MOVQ $0, "".~r1+16(FP)
0x0009 LEAQ "".~r1+24(FP), DI
0x000e XORPS X0, X0
0x0011 ADDQ $-16, DI
0x0015 DUFFZERO $288
0x0028 MOVQ "".i+8(FP), AX
0x002d CMPQ AX, $1
0x0031 JEQ $0, 199
0x0037 CMPQ AX, $2
0x003b JEQ $0, 155
0x003d CMPQ AX, $3
0x0041 JNE 111
0x0043 MOVQ "".statictmp_2(SB), AX
0x004a MOVQ AX, "".~r1+16(FP)
0x004f LEAQ "".~r1+24(FP), DI
0x0054 LEAQ "".statictmp_2+8(SB), SI
0x005b DUFFCOPY $854
0x006e RET
0x006f MOVQ "".statictmp_3(SB), AX
0x0076 MOVQ AX, "".~r1+16(FP)
0x007b LEAQ "".~r1+24(FP), DI
0x0080 LEAQ "".statictmp_3+8(SB), SI
0x0087 DUFFCOPY $854
0x009a RET
0x009b MOVQ "".statictmp_1(SB), AX
0x00a2 MOVQ AX, "".~r1+16(FP)
0x00a7 LEAQ "".~r1+24(FP), DI
0x00ac LEAQ "".statictmp_1+8(SB), SI
0x00b3 DUFFCOPY $854
0x00c6 RET
0x00c7 MOVQ "".statictmp_0(SB), AX
0x00ce MOVQ AX, "".~r1+16(FP)
0x00d3 LEAQ "".~r1+24(FP), DI
0x00d8 LEAQ "".statictmp_0+8(SB), SI
0x00df DUFFCOPY $854
0x00f2 RET

All fine and dandy, but if that looks a bit repetitive to you, you are quite right. Essentially for each of the return statements the object to be returned is more or less allocated/initialized (or more precisely copied via the DUFFCOPYmacro).

naked return feature of golang

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func NamedReturnParams(i int) (oi objectInfo) {

if i == 1 {
// Do one thing
return
}

if i == 2 {
// Do another thing
return
}

if i == 3 {
// Do one more thing still
return
}

// Normal return
return
}

It reduces the size of the function down from 243 to 67 bytes. Also as an additional benefit you will save some CPU cycles upon exiting out because there is no need anymore to do anything in order to setup the return value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// parse credentialHeader string into its structured form.
func parseCredentialHeader(credElement string) (ch credentialHeader) {
creds := strings.Split(strings.TrimSpace(credElement), "=")
if len(creds) != 2 {
return
}
if creds[0] != "Credential" {
return
}
credElements := strings.Split(strings.TrimSpace(creds[1]), "/")
if len(credElements) != 5 {
return
}
if false /*!isAccessKeyValid(credElements[0])*/ {
return
}
// Save access key id.
cred := credentialHeader{
accessKey: credElements[0],
}
var e error
cred.scope.date, e = time.Parse(yyyymmdd, credElements[1])
if e != nil {
return
}
cred.scope.region = credElements[2]
if credElements[3] != "s3" {
return
}
cred.scope.service = credElements[3]
if credElements[4] != "aws4_request" {
return
}
cred.scope.request = credElements[4]
return cred
}

隐含的return value的方式

Note that actually the ch variable is a normal local variable just like any other local variable that is defined within the function. And as such you can change its value from the default ‘zero’ state (but of course then the modified version will be returned upon exiting out).

others uses of named return values

As pointed out by several persons, another benefit of named return values is the use in closures (i.e. defer statements). Thus one may access the named return value in a function that is called as the result of a defer statement and act accordingly.

conclusion

So we will be gradually adopting named return values more and more, both for new code as well as for existing code.

future to integration with gofmt to modify the source automatically

go performance optimization workflow:

  • determine your performance goals
  • profile to identify the areas to improve. This can be CPU, heap allocations, or goroutine blocking
    • CPU
    • heap allocation
    • goroutine blocking
  • benchmark to determine the speed up your solution will provide using the built-in benchmarking framework (http://golang.org/pkg/testing/)
  • profile again afterwards to verify the issue is gone
  • use https://godoc.org/golang.org/x/perf/benchstat or https://github.com/codahale/tinystat to verify that a set of timings are ‘sufficiently’ different for an optimization to be worth the added code complexity

The basic rules of the game are:

  1. minimize CPU usage
    • do less work
    • this generally means “a faster algorithm”
    • but CPU caches and the hidden constants in O() can play tricks on you
  2. minimize allocations (which leads to less CPU stolen by the GC)
  3. make your data quick to access

Basic

Introductory Pofiling

  • pprof
  • Writing and running (micro)benchmarks
    • -cpuprofile
    • -memprofile
    • -benchmem
  • how to read it pprof output
  • macro-benchmarks, net/http/pprof

Tracer

  • Techniques specific to the architecture running the code
  • introduction to CPU caches
    • building intuition around cache-lines: sizes, padding, alignment
    • false-sharing
    • OS tools to view cache-misses
  • branch prediction

Heap Allocations

  • Understanding escape analysis

Runtime

  • cost of calls via interfaces (indirect calls on the CPU level)
  • runtime.convT2E / runtime.convT2I
  • type assertions vs. type switches
  • defer
  • special-case map implementations for ints, strings

Common gotchas with the standard library

  • time.After() leaks until it fires
  • Reusing HTTP connections…
  • ….

Alternate implementions

  • Popular replacements for standard library packages:
    • encoding/json -> ffjson
    • net/http -> fasthttp
    • regexp -> ragel (or other regular expression package)
    • serialization
      • encoding/gob
      • protobuf

perf(perf2pprof)

PageRank的相关说明

  • 整个互联网,看做一张有向图
    • 网页是图上的点
    • 链接是图上的又向边
  • 每个网页有一个权威评分,称作pagerank,可以把它当做一种投票权
  • 将每个超链接作为一次投票
    • 每个网页的pagerank等于所有指向该网页超链接的网页的pagerank的加权和
    • 这些权值等于这些网页各自向外链接数目的倒数

里面主要的点:

  • 足够优美,表达简单
  • 关于加权和部分,计算方式聪明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

class Vertex:
def __init__(self):
self.in_degree = 0
self.out_degree = 0
self.pagerank = 0.0

class Edge:
def __init__(self, start, end):
self.start_id = start
self.end_id = end

def addVertex(vertex_name, vtx_map):
'''
return the id of vertex_name
if exists in vtx_map, return directly
if not exists, add it, and then return

vertex_name: string, the url of a web page
vtx_map: dict, the map from url to id
'''
res_id = 0
if vertex_name in vtx_map:
return vtx_map[vertex_name]
else:
res_id = len(vtx_map)
vtx_map[vertex_name] = res_id
return res_id

def readTable(fname, vtx_map, edge_list):
'''
read fname line by line, update the vtx_map and edge_list

fname: string, the file name of the table
vtx_map: dict, the map from url to id
edge_list: list, the list of all edges
'''
with open(fname, 'r') as fin:
for line in fin.readlines():
tmp = line.strip().split('\t')
assert(len(tmp) == 2)
start = addVertex(tmp[0], vtx_map)
end = addVertex(tmp[1], vtx_map)
edge_list.append(Edge(start, end))
return None

def initialize(vtx_map, edge_list, vtx_list):
'''
initialize the data structures

vtx_map: dict, the map from url to id
edge_list: list, the list of all edges
vtx_list: list, the list of all vertices
'''
vtx_num = len(vtx_map)
assert(vtx_num > 0)
vtx_list = [Vertex() for _ in range(vtx_num)]
for i in range(vtx_num):
vtx_list[i].pagerank = 1.0 / vtx_num
for edge in edge_list:
vtx_list[edge.start_id].out_degree += 1
vtx_list[edge.end_id].in_degree += 1
return None

def calcPagerank(alpha, num_iter, vtx_map, edge_list):
'''
calc PageRank for all vertices
return: vtx_list, list, the list of all vertices

alpha: float, damping factor
num_iter: int, the upper limitation of calculation
vtx_map: dict, the map from url to id
edge_list: list, the list of all edges
'''
vtx_list, pr_list = list(), list()
initialize(vtx_map, edge_list, vtx_list)
vtx_num = len(vtx_list)
assert(vtx_num > 0)
alpha = float(alpha)
for _ in range(num_iter):
pr_list = [alpha / vtx_num for _ in range(vtx_num)]
# calc
for edge in edge_list:
pr_list += (1 - alpha) * vtx_list[edge.start_id].pagerank / \
vtx_list[edge.start_id].out_degree
# revise
revise = sum(map(lambda vtx: (1 - alpha) * vtx.pagerank / vtx_num, \
filter(lambda vtx:(vtx.out_degree == 0), vtx_list)))
# update
for i in range(vtx_num):
vtx_list[i].pagerank = pr_list[i] + revise
return vtx_list

def doCalcPageRank(fname = 'wt2g_inlinks.source', alpha = 0.15, num_iter = 30):
vtx_map = dict()
edge_list = list()
readTable(fname, vtx_map, edge_list)
return calcPagerank(alpha, num_iter, vtx_map, edge_list)

if __name__ == '__main__':
print doCalcPageRank()


相关程序说明:

莫道不肝肠

没有人会给你这么多耐心,来容忍你这样的拖拉,你这样中二的感觉。。

真当是说出口的那一句,还是。。

承诺不了,就不要去说大话了,只会让自己都看轻自己。。

其实还是胆小,自己不擅长的事情,不敢去做,不敢去承担,只想着逃避,who care you

之前已经打算好了,何故做小女儿态。。

做不了别人眼中的自己,做好自己眼中的自己,算是一个卑微的acer的一点梦想吧。。