書籍:The Way To Go,第三部分

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

Error handling

  • error interface

type error interface {     Error() string}

  • defining errors :import "errors"

var errNotFound error = errors.New("Not found error")err := errors.New("math – square root of negative number")
  • custom error

type PathError struct {     Op string     Path string     Err error}
  • panic and recover

panic("A severe error occurred: stopping the program!")
package parse// importtype ParseError struct {    Index int          Word  string       Error err}func (e *ParseError) String() string {    return fmt.Sprintf("...error parsing %q as int", e.Word)}func Parse(input string) (numbers []int, err error) {      defer func() {          if r := recover(); r != nil {              var ok bool              err, ok = r.(error)              if !ok {                  err = fmt.Errorf("pkg: %v", r)              }          }    }()    fields := strings.Fields(input)    numbers = fields2numbers(fields)     return}func fields2numbers(fields []string) (numbers []int) {    if len(fields) == 0 {        panic("no words to parse")    }    for idx, field := range fields {        num, err := strconv.Atoi(field)        if err != nil {            panic(&ParseError{idx, field, err})        }        numbers = append(numbers, num)    }    return}
package mainimport (    "fmt"    "./parse/parse")func main() {    var examples = []string{"1 2 3 4 5", ..., }    for _, ex := range examples {        fmt.Printf("Parsing %q:\n  ", ex)            nums, err := parse.Parse(ex)            if err != nil {            fmt.Println(err)             continue        }        fmt.Println(nums)    }}

Starting an external command or program

  •  StartProcess

package mainimport (                          "fmt"                             "os/exec"                     "os"              )                            func main() {                     // os.StartProcess      env := os.Environ()           procAttr := &os.ProcAttr{           Env: env,                       Files: []*os.File{                  os.Stdin,                         os.Stdout,                        os.Stderr,                    },     }           pid, err := os.StartProcess("/bin/ls", []string{"ls", "-l"}, procAttr)       if err != nil {           fmt.Printf("Error %v starting process!", err) //            os.Exit(1)     }     fmt.Printf("The process id is %v", pid)     ...
  • cmd.Run

cmd := exec.Command("gedit")         // this opens a gedit-windowerr := cmd.Run()if err != nil {     fmt.Printf("Error %v executing command!", err)      os.Exit(1)}fmt.Printf("The command is %v", cmd)

Testing and Debugging

  • Simulate Breakpoint

where := func() {     _, file, line, _ := runtime.Caller(1)     log.Printf("%s:%d", file, line)}
  • Garbage Collection

runtime.GC()fmt.Printf("%d\n", runtime.MemStats.Alloc/1024)runtime.SetFinalizer(obj, func(obj *typeObj))
  • test functions

  1. func (t *T) Fail()

    ü   marks the test function as having failed, but continues its execution.

  2. func (t *T) FailNow()

    ü   marks the test function as having failed and stops its execution;

    ü   all other tests in this file are also skipped, execution continues with the next test file

  3. func (t *T) Log(args …interface{})

    ü   the args are formatted using default formatting and the text  is logged in the error-log

  4. func (t *T) Fatal(args …interface{})

    ü   this has the combined effect of c) followed by b)

  • a concrete example

ü   test programs must be within the same package

ü   the files must have names of the form *_test.go
package mainimport (     "fmt"     "./even/even")func main() {     for i:=0; i<=100; i++ {          fmt.Printf("Is the integer %d even? %v\n", i, even.Even(i))      }}
package evenfunc Even(i int) bool {        // Exported functions     return i%2 == 0}func Odd(i int) bool {      return i%2 != 0}
package evenimport "testing"func TestEven(t *testing.T) {     if !Even(10) {         t.Log("10 must be even!")         t.Fail()     }     if Even(7) {         t.Log("7 is not even!")         t.Fail()     }}func TestOdd(t *testing.T) {     if !Odd(11) {         t.Log("11 must be odd!")         t.Fail()     }     if Odd(10) {         t.Log("10 is not odd!")         t.Fail()     }}
// Using table-driven testsvar tests = []struct{       // Test table     in  string     out string}{     {"in1", "exp1"},     {"in2", "exp2"},     ...}func TestFunction(t *testing.T) {     for i, tt := range tests {         s := FuncToBeTested(tt.in)              verify(t, i, "FuncToBeTested: ", tt.in, s, tt.out)     }}func verify(t *testing.T, testnum int, testcase, input, output, expected string)  {     if input != output {         t.Errorf("%d. %s with input = %s: output %s != %s",                         testnum, testcase, input, output, expected)     }}
// investigating performance// go test –x –v –cpuprofile=cpuprof.out –file x_test.go// go test –x –v –memprofile=memprof.out –file x_test.govar cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")func main() {     flag.Parse()     if *cpuprofile != "" {         f, err := os.Create(*cpuprofile)         if err != nil {              log.Fatal(err)         }         pprof.StartCPUProfile(f)         defer pprof.StopCPUProfile()     }     ...// progexec -cpuprofile=progexec.prof// gopprof progexec progexec.prof// Some of the interesting commands of this tool are:// a)    topN: shows the top N samples in the profile// b)    web or web funcname: writes a graph of the profile data in SVG format// list funcname or weblist funcname
// If it is seen that the function runtime.mallocgc (which both allocates and runs periodic garbage // collections) is heavily used, then it is time for memory profiling.// var  memprofile  =  flag.String("memprofile",  "",  "write  memory  profile  to  this file")// ...CallToFunctionWhichAllocatesLotsOfMemory()if *memprofile != "" {     f, err := os.Create(*memprofile)     if err != nil {         log.Fatal(err)     }     pprof.WriteHeapProfile(f)     f.Close()     return}// progexec -memprofile=progexec.mprof// gopprof progexec progexec.mprof// gopprof --inuse_objects progexec progexec.mprof
// For web applications:import _ "http/pprof"// gopprof http://localhost:6060/debug/pprof/profile # 30-second CPU profile// gopprof http://localhost:6060/debug/pprof/heap # heap profile

Goroutines

  1. runtime.Gosched() / runtime.Goexit()

  2. An experiential rule of thumb seems to be that for n cores setting GOMAXPROCS  to n-1 yields the best performance, and the following should also be followed:  number of goroutines > 1 + GOMAXPROCS > 1

var numCores = flag.Int("n", 2, "number of CPU cores to use")runtime.GOMAXPROCS(*numCores)
  • goroutine example 1

func main() {    go longWait()    go shortWait()    fmt.Println("About to sleep in main()")    time.Sleep(10 * 1e9)      fmt.Println("At the end of main()")}func longWait() {    fmt.Println("Beginning longWait()")    time.Sleep(5 * 1e9)              // sleep for 5 seconds    fmt.Println("End of longWait()")}func shortWait() {    fmt.Println("Beginning shortWait()")    time.Sleep(2 * 1e9)              // sleep for 2 seconds    fmt.Println("End of shortWait()")}

Channels

var ch1 chan stringch1 = make(chan string)ch1 := make(chan string)buf := 100ch1 := make(chan string, buf)chanOfChans := make(chan chan int)funcChan := chan func()
func main() {    ch := make(chan string)    go sendData(ch)    go getData(ch)    time.Sleep(1e9)}func sendData(ch chan string) {    ch <- “Washington”    ch <- “Tripoli”    ch <- “London”}func getData(ch chan string) {    var input string    for {         input = <-ch;         fmt.Printf("%s ", input)     }}
  • Semaphore pattern

type Empty interface {}var empty Empty...data := make([]float64, N)res := make([]float64, N)sem := make(chan Empty, N)      // semaphore ...for i, xi := range data {     go func (i int, xi float64) {           res[i] = doSomething(i,xi)           sem <- empty     } (i, xi)}for i := 0; i < N; i++ {      // wait for goroutines to finish     <-sem }
  • Channel Factory pattern

func main() {    stream := pump()    go suck(stream)        // shortened : go suck( pump() )    time.Sleep(1e9)}func pump() chan int {    ch := make(chan int)    go func() {        for i := 0; ; i++ {            ch <- i        }    }()    return ch}func suck(ch chan int) {    for {        fmt.Println(<-ch)    }}func suck(ch chan int) {    go func() {        for v := range ch {            fmt.Println(v)        }    }()}
  • Channel Directionality

// channel can only receive data and cannot be closedvar send_only chan<- intvar recv_only <-chan int        // channel can only send data...var c = make(chan int)          // bidirectionalgo source(c)go sink(c)func source(ch chan<- int) {    for { ch <- 1 }}func sink(ch <-chan int) {    for { <-ch }}...// closing a channelfunc sendData(ch chan string) {     ch <- "Washington"     ch <- "Tripoli"     ch <- "London"     ch <- "Beijing"     ch <- "Tokio"     close(ch)}func getData(ch chan string) {     for {          input, open := <-ch          if !open {               break          }          fmt.Printf("%s ", input)     }}
  • Switching between goroutines with select

select {case u:= <- ch1:     ...case v:= <- ch2: ...default: // no value ready to be received  ...}
  1. if all are blocked, it waits until one can proceed 

  2. if multiple can proceed, it chooses one at random.

  3. when none of the channel operations can proceed and the default clause is present, then this is executed: the default is always runnable (that is: ready to execute). Using a send operation in a select statement with a default case guarantees that the send will be non-blocking!

  • channels with timeouts and tickers

// func Tick(d Duration) <-chan Timeimport "time"rate_per_sec := 10var dur Duration = 1e8          // rate_per_secchRate := time.Tick(dur)        // every 1/10th of a secondfor req := range requests {    <- chRate                   // rate limit our Service.Method RPC calls    go client.Call("Service.Method", req, ...)}
// func After(d Duration) <-chan Timefunc main() {     tick := time.Tick(1e8)     boom := time.After(5e8)    for {        select {            case <-tick:                fmt.Println(“tick.”)            case <-boom:                fmt.Println(“BOOM!”)                return            default:                fmt.Println(“    .”)                time.Sleep(5e7)         }     }}
  • using recover with goroutines

func server(workChan <-chan *Work) {    for work := range workChan {        go safelyDo(work)     }}func safelyDo(work *Work) {    defer func() {        if err := recover(); err != nil {            log.Printf(“work failed with %s in %v:”, err, work)        }    }()    do(work)}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.