原文:https://dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go

There is no pass-by-reference in Go
My post on pointers provoked a lot of debate about maps and pass by reference semantics. This post is a response to those debates.

To be clear, Go does not have reference variables, so Go does not have pass-by-reference function call semantics.

What is a reference variable?
In languages like C++ you can declare an alias, or an alternate name to an existing variable. This is called a reference variable.

#include <stdio.h>

int main() {
        int a = 10;
        int &b = a;
        int &c = b;

        printf("%p %p %p\n", &a, &b, &c); // 0x7ffe114f0b14 0x7ffe114f0b14 0x7ffe114f0b14
        return 0;
}

You can see that a, b, and c all refer to the same memory location. A write to a will alter the contents of b and c. This is useful when you want to declare reference variables in different scopes–namely function calls.

Go does not have reference variables
Unlike C++, each variable defined in a Go program occupies a unique memory location.

package main

import "fmt"

func main() {
        var a, b, c int
        fmt.Println(&a, &b, &c) // 0x1040a124 0x1040a128 0x1040a12c
}

It is not possible to create a Go program where two variables share the same storage location in memory. It is possible to create two variables whose contents point to the same storage location, but that is not the same thing as two variables who share the same storage location.

package main

import "fmt"

func main() {
        var a int
        var b, c = &a, &a
        fmt.Println(b, c)   // 0x1040a124 0x1040a124
        fmt.Println(&b, &c) // 0x1040c108 0x1040c110
}

In this example, b and c hold the same value–the address of a–however, b and c themselves are stored in unique locations. Updating the contents of b would have no effect on c.

But maps and channels are references, right?
Wrong. Maps and channels are not references. If they were this program would print false.

package main

import "fmt"

func fn(m map[int]int) {
        m = make(map[int]int)
}

func main() {
        var m map[int]int
        fn(m)
        fmt.Println(m == nil)
}

If the map m was a C++ style reference variable, the m declared in main and the m declared in fn would occupy the same storage location in memory. But, because the assignment to m inside fn has no effect on the value of m in main, we can see that maps are not reference variables.

Conclusion
Go does not have pass-by-reference semantics because Go does not have reference variables.

Next: If a map isn’t a reference variable, what is it?

Related Posts:
If a map isn’t a reference variable, what is it?
Declaration scopes in Go
Understand Go pointers in less than 800 words or your money back
What is the zero value, and why is it useful ?
This entry was posted in Go, Programming and tagged pass by reference, pass by value, references on April 29, 2017.

原文地址 http://commaok.xyz/post/compile-time-assertions/
This post is about a little-known way to make compile-time assertions in Go. You probably shouldn’t use it, but it is interesting to know about.

As a warm-up, here’s a fairly well-known form of compile-time assertions in Go: Interface satisfaction checks.

In this code (playground), the var _ = line ensures that type W is a stringWriter, as checked for by io.WriteString.

package main

import "io"

type W struct{}

func (w W) Write(b []byte) (int, error)       { return len(b), nil }
func (w W) WriteString(s string) (int, error) { return len(s), nil }

type stringWriter interface {
    WriteString(string) (int, error)
}

var _ stringWriter = W{}

func main() {
    var w W
    io.WriteString(w, "very long string")
}

If you comment out W’s WriteString method, the code will not compile:

main.go:14: cannot use W literal (type W) as type stringWriter in assignment:

W does not implement stringWriter (missing WriteString method)

This is useful. For most types that satisfy both io.Writer and stringWriter, if you eliminate the WriteString method, everything will continue to work as it did before, but with worse performance.

Rather than trying to write a fragile test for a performance regression using testing.T.AllocsPerRun, you can simply protect your code with a compile-time assertion.

Here’s a real world example of this technique from package io.

OK, onward to obscurity!

Interface satisfaction checks are great. But what if you wanted to check a plain old boolean expression, like 1+1==2?

Consider this code (playground):

package main

import "crypto/md5"

type Hash [16]byte

func init() {
    if len(Hash{}) < md5.Size {
        panic("Hash is too small")
    }
}

func main() {
    // ...
}

Hash is perhaps some kind of abstracted hash result. The init function ensures that it will work with crypto/md5. If you change Hash to be (say) [8]byte, it’ll panic when the process starts. However, this is a run-time check. What if we wanted it to fail earlier?

Here’s how. (There’s no playground link, because this doesn’t work on the playground.)

package main

import "C"

import "crypto/md5"

type Hash [16]byte

func hashIsTooSmall()

func init() {
    if len(Hash{}) < md5.Size {
        hashIsTooSmall()
    }
}

func main() {
    // ...
}

Now if you change Hash to be [8]byte, it will fail during compilation. (Actually, it fails during linking. Close enough for our purposes.)

$ go build .
# demo
main.hashIsTooSmall: call to external function
main.init.1: relocation target main.hashIsTooSmall not defined
main.init.1: undefined: "main.hashIsTooSmall"

What’s going on here?

hashIsTooSmall is declared without a function body. The compiler assumes that someone else will provide an implementation, perhaps an assembly routine.

When the compiler can prove that len(Hash{}) < md5.Size, it eliminates the code inside the if statement. As a result, no one uses the function hashIsTooSmall, so the linker eliminates it. No harm done. As soon as the assertion fails, the code inside the if statement is preserved. hashIsTooSmall can’t be eliminated. The linker then notices that no one else has provided an implementation for the function and fails with an error, which was the goal.

One last oddity: Why import "C"? The go tool knows that in normal Go code, all functions must have bodies, and instructs the compiler to enforce that. By switching to cgo, we remove that check. (If you run go build -x on the code above, without the import "C" line, you will see that the compiler is invoked with the -complete flag.) An alternative to adding import "C" is to add an empty file called foo.s to the package.

I know of only one use of this technique, in the compiler test suite. There are other imaginable places to apply it, but no one has bothered.

And that’s probably how it should be. :)

原文地址 https://rakyll.org/pprof-ui/

pprof user interface
Tue, Oct 10, 2017
pprof now is coming with a Web UI. In order to try it out, go get the pprof tool:

$ go get github.com/google/pprof

The tool launches a web UI if -http flag is provided. For example, in order to launch the UI with an existing profile data, run the following command:

$ pprof -http=:8080 profile.out

You can focus, ignore, hide, and show with regexp. As well as clicking on the boxes and using the refining menu also works:
请输入图片描述

You can peek, list, and disassemble and box. Especially listing is a frequently used feature to understand the cost by line:

请输入图片描述

You can also have the regular listing view and use regexp filtering to focus, ignore, hide and show.

请输入图片描述

Recently, web UI added support for flame graphs. The pprof tool is now able to display flame graphs without any external dependencies!

请输入图片描述

The Web UI is going to be in Go 1.10, but you can try it by go getting from head and report bugs and improvements!

原文: https://go101.org/article/channel-closing.html
How To Gracefully Close Channels
Several days ago, I wrote an article which explains the channel rules in Go. That article got many votes on reddit and HN.

I collected some criticisms on the following designs and rules of Go channels:
no easy and universal ways to check whether or not a channel is closed without modifying the status of the channel.
closing a closed channel will panic, so it is dangerous to close a channel if the closers don't know whether or not the channel is closed.
sending values to a closed channel will panic, so it is dangerous to send values to a channel if the senders don't know whether or not the channel is closed.
The criticisms look reasonable (in fact not). Yes, there is not a built-in function to check whether or not a channel has been closed.

There is indeed a simple method to check whether or not a channel is closed if you can make sure no values were ever sent to the channel (this method will be often used in other examples in this article):
package main

import "fmt"

type T int

func IsClosed(ch <-chan T) bool {
    select {
    case <-ch:
        return true
    default:
    }
    
    return false
}

func main() {
    c := make(chan T)
    fmt.Println(IsClosed(c)) // false
    close(c)
    fmt.Println(IsClosed(c)) // true
}

As above mentioned, this is not a universal way to check whether a channel is closed.

However, even if there is a simple closed(chan T) bool function to check whether or not a channel has been closed, its usefulness would be very limited, just like the built-in len function for checking the current number of values stored in the value buffer of a channel. The reason is the status of the checked channel may have changed just after a call to such functions returns, so that the returned value has already not be able to reflect the latest status of the just checked channel. Although it is okay to stop sending values to a channel ch if the call closed(ch) returns true, it is not safe to close the channel or continue sending values to the channel if the call closed(ch) returns false.

The Channel Closing Principle
One general principle of using Go channels is don't close a channel from the receiver side and don't close a channel if the channel has multiple concurrent senders. In other words, you should only close a channel in a sender goroutine if the sender is the only sender of the channel.

(Below, we will call the above principle as channel closing principle.)

Surely, this is not a universal principle to close channels. The universal principle is don't send values to (or close) closed channels. If an arbitrary goroutine can guarantee that no goroutines will send to (or close) a non-closed non-nil channel any more, then that goroutine can close the channel safely. However, making such guarantees by a receiver or by one of many senders of a channel usually needs much effort, and often makes code complicated. On the contrary, it is much easy to hold the channel closing principle mentioned above.

Solutions Which Close Channels Rudely
If you would close a channel from the receiver side or in one of the multiple senders of the channel anyway, then you can use the recover mechanism to prevent the possible panic from crashing your program. Here is an example (assume the channel element type is T).

func SafeClose(ch chan T) (justClosed bool) {
    defer func() {
        if recover() != nil {
            // The return result can be altered
            // in a defer function call.
            justClosed = false
        }
    }()
    
    // assume ch != nil here.
    close(ch)   // panic if ch is closed
    return true // <=> justClosed = true; return
}

This solution obviously breaks the channel closing principle.

The same idea can be used for sending values to a potential closed channel:

func SafeSend(ch chan T, value T) (closed bool) {
    defer func() {
        if recover() != nil {
            closed = true
        }
    }()
    
    ch <- value  // panic if ch is closed
    return false // <=> closed = false; return
}
Solutions Which Close Channels Politely
Many people prefer using sync.Once to close channels:
type MyChannel struct {
    C    chan T
    once sync.Once
}

func NewMyChannel() *MyChannel {
    return &MyChannel{C: make(chan T)}
}

func (mc *MyChannel) SafeClose() {
    mc.once.Do(func() {
        close(mc.C)
    })
}
Surely, we can also use sync.Mutex to avoid closing a channel multiple times:
type MyChannel struct {
    C      chan T
    closed bool
    mutex  sync.Mutex
}

func NewMyChannel() *MyChannel {
    return &MyChannel{C: make(chan T)}
}

func (mc *MyChannel) SafeClose() {
    mc.mutex.Lock()
    defer mc.mutex.Unlock()
    if !mc.closed {
        close(mc.C)
        mc.closed = true
    }
}

func (mc *MyChannel) IsClosed() bool {
    mc.mutex.Lock()
    defer mc.mutex.Unlock()
    return mc.closed
}

We should comprehend that the reason of why Go doesn't support built-in SafeSend and SafeClose functions is that it is not recommended to close a channel from the receiver side or from multiple concurrent senders. Go even forbids closing receive-only channels.

Solutions Which Close Channels Gracefully
One drawback of the above SafeSend function is that its calls can't be used as send operations which follow the case keyword in select blocks. The other drawback of the above SafeSend and SafeClose functions is that many people, including me, would think the above solutions by using panic/recover and sync package are not graceful. Following, some pure-channel solutions without using panic/recover and sync package will be introduced, for all kinds of situations.

(In the following examples, sync.WaitGroup is used to make the examples complete. It may be not always essential to use it in real practice.)

1. M receivers, one sender, the sender says "no more sends" by closing the data channel

This is the simplest situation, just let the sender close the data channel when it doesn't want to send more:

package main

import (
    "time"
    "math/rand"
    "sync"
    "log"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    log.SetFlags(0)
    
    // ...
    const MaxRandomNumber = 100000
    const NumReceivers = 100
    
    wgReceivers := sync.WaitGroup{}
    wgReceivers.Add(NumReceivers)
    
    // ...
    dataCh := make(chan int, 100)
    
    // the sender
    go func() {
        for {
            if value := rand.Intn(MaxRandomNumber); value == 0 {
                // The only sender can close the channel safely.
                close(dataCh)
                return
            } else {            
                dataCh <- value
            }
        }
    }()
    
    // receivers
    for i := 0; i < NumReceivers; i++ {
        go func() {
            defer wgReceivers.Done()
            
            // Receive values until dataCh is closed and
            // the value buffer queue of dataCh is empty.
            for value := range dataCh {
                log.Println(value)
            }
        }()
    }
    
    wgReceivers.Wait()
}

2. One receiver, N senders, the receiver says "please stop sending more" by closing an additional signal channel

This is a situation a little more complicated than the above one. We can't let the receiver close the data channel, for doing this will break the channel closing principle. But we can let the receiver close an additional signal channel to notify senders to stop sending values:

package main

import (
    "time"
    "math/rand"
    "sync"
    "log"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    log.SetFlags(0)
    
    // ...
    const MaxRandomNumber = 100000
    const NumSenders = 1000
    
    wgReceivers := sync.WaitGroup{}
    wgReceivers.Add(1)
    
    // ...
    dataCh := make(chan int, 100)
    stopCh := make(chan struct{})
        // stopCh is an additional signal channel.
        // Its sender is the receiver of channel dataCh.
        // Its reveivers are the senders of channel dataCh.
    
    // senders
    for i := 0; i < NumSenders; i++ {
        go func() {
            for {
                // The first select is to try to exit the goroutine
                // as early as possible. In fact, it is not essential
                // for this specified example, so it can be omitted.
                select {
                case <- stopCh:
                    return
                default:
                }
                
                // Even if stopCh is closed, the first branch in the
                // second select may be still not selected for some
                // loops if the send to dataCh is also unblocked.
                // But this is acceptable for this example, so the
                // first select block above can be omitted.
                select {
                case <- stopCh:
                    return
                case dataCh <- rand.Intn(MaxRandomNumber):
                }
            }
        }()
    }
    
    // the receiver
    go func() {
        defer wgReceivers.Done()
        
        for value := range dataCh {
            if value == MaxRandomNumber-1 {
                // The receiver of the dataCh channel is
                // also the sender of the stopCh channel.
                // It is safe to close the stop channel here.
                close(stopCh)
                return
            }
            
            log.Println(value)
        }
    }()
    
    // ...
    wgReceivers.Wait()
}

As mentioned in the comments, for the additional signal channel, its sender is the receiver of the data channel. The additional signal channel is closed by its only sender, which holds the channel closing principle.

In this example, the channel dataCh is never closed. Yes, channels don't have to be closed. A channel will be eventually garbage collected if no goroutines reference it any more, whether it is closed or not. So the gracefulness of closing a channel here is not to close the channel.

3. M receivers, N senders, random one of them says "let's end the game" by notifying a moderator to close an additional signal channel

This is a the most complicated situation. We can't let any of the receivers and the senders close the data channel. And we can't let any of the receivers close an additional signal channel to notify all senders and receivers to exit the game. Doing either will break the channel closing principle. However, we can introduce a moderator role to close the additional signal channel. One trick in this example is how to notify the moderator to close the additional signal channel:

package main

import (
    "time"
    "math/rand"
    "sync"
    "log"
    "strconv"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    log.SetFlags(0)
    
    // ...
    const MaxRandomNumber = 100000
    const NumReceivers = 10
    const NumSenders = 1000
    
    wgReceivers := sync.WaitGroup{}
    wgReceivers.Add(NumReceivers)
    
    // ...
    dataCh := make(chan int, 100)
    stopCh := make(chan struct{})
        // stopCh is an additional signal channel.
        // Its sender is the moderator goroutine shown below.
        // Its reveivers are all senders and receivers of dataCh.
    toStop := make(chan string, 1)
        // The channel toStop is used to notify the moderator
        // to close the additional signal channel (stopCh).
        // Its senders are any senders and receivers of dataCh.
        // Its reveiver is the moderator goroutine shown below.
    
    var stoppedBy string
    
    // moderator
    go func() {
        stoppedBy = <-toStop
        close(stopCh)
    }()
    
    // senders
    for i := 0; i < NumSenders; i++ {
        go func(id string) {
            for {
                value := rand.Intn(MaxRandomNumber)
                if value == 0 {
                    // Here, a trick is used to notify the moderator
                    // to close the additional signal channel.
                    select {
                    case toStop <- "sender#" + id:
                    default:
                    }
                    return
                }
                
                // The first select here is to try to exit the goroutine
                // as early as possible. This select blocks with one
                // receive operation case and one default branches will
                // be specially optimized as a try-receive operation by
                // the standard Go compiler.
                select {
                case <- stopCh:
                    return
                default:
                }
                
                // Even if stopCh is closed, the first branch in the
                // second select may be still not selected for some
                // loops (and for ever in theory) if the send to
                // dataCh is also non-blocking.
                // This is why the first select block above is needed.
                select {
                case <- stopCh:
                    return
                case dataCh <- value:
                }
            }
        }(strconv.Itoa(i))
    }
    
    // receivers
    for i := 0; i < NumReceivers; i++ {
        go func(id string) {
            defer wgReceivers.Done()
            
            for {
                // Same as the sender goroutine, the first select here
                // is to try to exit the goroutine as early as possible.
                // This select blocks with one send operation case and
                // one default branches will be specially optimized as
                // a try-send operation by the standard Go compiler.
                select {
                case <- stopCh:
                    return
                default:
                }
                
                // Even if stopCh is closed, the first branch in the
                // second select may be still not selected for some
                // loops (and for ever in theory) if the receive from
                // dataCh is also non-blocking.
                // This is why the first select block is needed.
                select {
                case <- stopCh:
                    return
                case value := <-dataCh:
                    if value == MaxRandomNumber-1 {
                        // The same trick is used to notify
                        // the moderator to close the
                        // additional signal channel.
                        select {
                        case toStop <- "receiver#" + id:
                        default:
                        }
                        return
                    }
                    
                    log.Println(value)
                }
            }
        }(strconv.Itoa(i))
    }
    
    // ...
    wgReceivers.Wait()
    log.Println("stopped by", stoppedBy)
}

In this example, the channel closing principle is still held.

Please note that the buffer size (capacity) of channel toStop is one. This is to avoid the first notification is missed when it is sent before the moderator goroutine gets ready to receive nitification from toStop.

We can also set the capacity of the toStop channel as the sum number of senders and receivers, then we don't need a try-send select block to notify the moderator.

        ...
        toStop := make(chan string, NumReceivers + NumSenders)
        ...
        value := rand.Intn(MaxRandomNumber)
        if value == 0 {
            toStop <- "sender#" + id
            return
        }
        ...
            if value == MaxRandomNumber-1 {
                toStop <- "receiver#" + id
                return
            }
        ...

4. more situations?

There are more situation variants based on the above three ones. For example, one variant based on the most complicated one may require the receivers read all the remaining values out of the buffered data channel. This would be easy to handle and this article will not cover it.

Although the above three situations can't cover all the Go channel using situations, they are the basic ones. Most situations in practice can be classified into the three ones.

Conclusion
There are no situations which will force you to break the channel closing principle. If you encounter such a situation, please rethink your design and rewrite you code.

Programming with Go channels is like making art.

原文 https://www.cnblogs.com/flyme/archive/2011/11/28/2265899.html

有时候在比对代码时,看到某些改动,但不清楚这个改动的作者和原因,也不知道对应的BUG号,也就是说无从查到这些改动的具体原因了~

【注】:某个文件的改动是有限次的,而且每次代码修改的提交都会有commit描述,我们可以从这里进行入手;

一、切换到目录

首先切换到要查看的文件所在的目录:

cd packages/apps/Mms/src/com/android/mms/ui/

二、git log --pretty

然后使用下面的命令可列出文件的所有改动历史,注意,这里着眼于具体的一个文件,而不是git库,如果是库,那改动可多了去了~

git log --pretty=oneline 文件名

如:

root@ubuntu:android_src/packages/apps/Mms/src/com/android/mms/ui# git log --pretty=oneline MessageItem.java 
27209385caf678abe878375a470f4edd67a2d806 fix to process force close when empty address contained in card
0e04b16f1dad7dc0a36e2235f7337bc656c365c7 display for 1970-1-1
e4abf3a213197491e0855e101117b59b5dc0160d HREF#13954 receive, store, and display wap push
356f6def9d3fb7f3b9032ff5aa4b9110d4cca87e HREF#16265_uim_show_time_error
350f9d34c35ab50bdb4b2d43fb3ff9780e6c73fa fix xxxx
715e32f97bd9d8ce4b5ba650b97ba4b137150456 Fix ANR from calling Contact.get()
fd8357ff5febab0141e1beb8dd3b26f70416b108 Fix missing From field
d130e2e6dc448fd80ecb70f0d31e3affb9888b9a fix bug 2112925: don't display zip file garbage content in MMS.
0e19f738c114f86d0d88825ee48966015fb48b6d Don't always show sent timestamp
52f854cbb75e8f9975c7e33216b828eb2f981095 Don't show Anonymous as the MMS sender
331864544ec51ba6807fc5471cc6d537b7fef198 add search capability
33a87f96f8c625aa10131a77a3968c97c4ec5a62 Remove all references to ContactInfoCache except those in Contact.
70c73e05a792832aa28da751cdaf3fa83a7b8113 Begin moving all conversation data behind a data model with a cache.
48da875f1beea835c6771977e5bd8a9aa3d4bc10 Begin adding UI unit tests to the Mms app.
66dde9460badebf8e740275cabde9cca256006eb Stop requiring a Context to be passed in to ContactInfoCache.
591d17e9a51bb9f829d6860dc7aa0bad25062cd5 auto import from //branches/cupcake_rel/...@138607
72735c62aba8fd2a9420a0f9f83d22543e3c164f auto import from //depot/cupcake/@135843
892f2c5bf965b1431ae107b602444a93f4aad4a3 auto import from //depot/cupcake/@135843
153ae99e0a7d626a24d61475eeb133249deb448c auto import from //depot/cupcake/@132589
abd7b2d90f7491075f1daba4b4cccdfc82f8ddd1 auto import from //depot/cupcake/@137055
59d72c57ce9c319b6cd43ce2ab36b7076c9e821f auto import from //branches/cupcake/...@132276
44cea74dc55e2459262d0d765ef4a69267dd09b0 auto import from //branches/cupcake/...@131421
0f236f55349f070ac94e12cca963847173393da8 Code drop from //branches/cupcake/...@124589
8eed706474910ccb978acda03e85d3261037da6e Initial Contribution

三、git show

如上所示,打印出来的就是针对文件MessageItem.java的所有的改动历史,每一行最前面的那一长串数字就是每次提交形成的哈希值,接下来使用git show即可显示具体的某次的改动的修改~

git show 356f6def9d3fb7f3b9032ff5aa4b9110d4cca87e

结果如下:

root@ubuntu:/android_src/packages/apps/Mms/src/com/android/mms/ui# git show 356f6def9d3fb7f3b9032ff5aa4b9110d4cca87e
commit 356f6def9d3fb7f3b9032ff5aa4b9110d4cca87e
Author: 某某某 <某某某的邮箱>
Date:   Thu Jan 6 01:50:31 2011 +0800

修改的描述(是该代码commit时所填)

Signed-off-by: 某某某 <某某某的邮箱>

diff --git a/src/com/android/mms/ui/MessageItem.java b/src/com/android/mms/ui/MessageItem.java

index 0a0c4b7..55c3b27 100644
--- a/src/com/android/mms/ui/MessageItem.java
+++ b/src/com/android/mms/ui/MessageItem.java
+
+ 列出具体的改动
-
-

这样就可以知道是谁做了修改,以及具体的修改代码~

那接下来不管是直接去找他交流还是研究代码,都有依据了~