目录
redeclare is ok
such as
f, err := os.Open(name)
...
d, err := f.Stat()
above such code, err used twice.
for
go use for instead of while and do while
// Like a C for
for init; condition; post { }
// Like a C while
for condition { }
// Like a C for(;;)
for { }
//If you're looping over an array, slice, string, or map, or reading from a channel, a range clause can manage the loop.
for key, value := range oldMap {
newMap[key] = value
}
//If you only need the first item in the range (the key or index), drop the second:
for key := range m {
if key.expired() {
delete(m, key)
}
}
//If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:
sum := 0
for _, value := range array {
sum += value
}
defer
Defer
Deferred functions are executed in LIFO order when return
defer doSomething
data
make creates slices, maps, and channels only
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
can be instead by
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd, name, nil, 0}
}
printf
func Printf(format string, v ...interface{}) (n int, err error) {}
// v is any number of any type
// btw, below is the usage of ...
func Min(a ...int) int {
min := int(^uint(0) >> 1) // largest int
for _, i := range a {
if i < min {
min = i
}
}
return min
}
interface
Go type 不需要显式声明它实现了接口,仅通过实现接口来实现接口
// embedding
type Job struct {
Command string
*log.Logger // as implement interface
}
func (job *Job) Printf(format string, args ...interface{}) {
job.Logger.Printf("%q: %s", job.Command, fmt.Sprintf(format, args...))
}
concurrency
Do not communicate by sharing memory; instead, share memory by communicating.
add go before func to make it run concurrently
func Announce(message string, delay time.Duration) {
go func() {
time.Sleep(delay)
fmt.Println(message)
}() // Note the parentheses - must call the function.
}
on above, go func is closures, how to sent signal? Use channels
channels
channels like the slide with semaphore.
// init
// if no buffer, <-ci wait until something -> ci
ci := make(chan int) //no buffer
cj := make(chan int,10)//buffer
go func() 内存共享
// 不能确保 req 是唯一的
func Serve(queue chan *Request) {
for req := range queue {
sem <- 1
go func() {
process(req) // Buggy; see explanation below.
<-sem
}()
}
}
//solve1: args sent to func
func Serve(queue chan *Request) {
for req := range queue {
sem <- 1
go func(req *Request) {
process(req)
<-sem
}(req)
}
}
//solve2: redeclare
func Serve(queue chan *Request) {
for req := range queue {
req := req // Create new instance of req for the goroutine.
sem <- 1
go func() {
process(req)
<-sem
}()
}
}
server by channels
func handle(queue chan *Request) {
for r := range queue {
process(r)
}
}
func Serve(clientRequests chan *Request, quit chan bool) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
go handle(clientRequests)
}
<-quit // Wait to be told to exit.
}
go concurrency
涉及到并发 data race 都需要用锁。 如果不需要等待,那么可以用 mutex 若需要等待,
chan := make(channel bool)
var wg sync.WaitGroup
var mu sync.Mutex
cond := sync.NewCond(&mu) // 需要用到 broadcast 的地方才需要 cond,不然直接 chan
go channels: synchronous communication mechanism 如果是 unbuffer channels,那么无论是只有发送方还是只有接收方,都会造成阻塞,因为 channels 的本质是同步(buffer channel 也只会延迟这个过程)。
goroutine & mu
# no race
func Lock_() {
task := Task{
mu: sync.Mutex{},
peers: nil,
}
for i := 0; i < 10000; i++ {
task.peers = append(task.peers, i+i)
}
var wg sync.WaitGroup
wg.Add(len(task.peers))
task.mu.Lock()
for i, i2 := range task.peers {
go func(i int, i2 int) {
defer wg.Done()
task.mu.Lock()
fmt.Printf("%v %v\n", i, i2)
task.mu.Unlock()
}(i, i2)
}
task.mu.Unlock()
wg.Wait()
}
go gc
如果数组需要改动,将不需要的部分设为 nil,可以让 gc 识别到并回收。
go pprof
go test -run TestSpeed3A -memprofile mem.prof
go tool pprof -http=:8081 mem.prof
dstest -v2 -s -p10 -n10 -o log -r $(grep -oE '^func Test[A-Za-z0-9_]+' test_test.go | sed 's/^func //; s/(.*)//')