@zhongdao
2021-03-02T12:35:05.000000Z
字数 13231
阅读 1976
未分类
cat ~/go/src/test/greet.go
package mainimport ("fmt""test/util")func main(){info := util.Info{15}fmt.Println(info.Age)fmt.Println(util.Greeting())}
cat ~/go/src/test/util/util.go
package utiltype Info struct{Age int}func Greeting()string{return "world hello"}
编译时:
go run greet.go 即可
遇到提示:
go run greet.gobuild command-line-arguments: cannot load greet/util: malformed module path "greet/util": missing dot in first path element
说明是go.1.13的高版本,从Go 1.13开始,模块module模式将是所有开发的默认模式。
需要执行如下命令
go mod init
cat greet2.go
package mainimport ("fmt")func main(){info := Info{15}fmt.Println(info.Age)fmt.Println(Greeting())}
cat util.go
package maintype Info struct{Age int}func Greeting()string{return "world hello"}
go run greet2.go util.go 即可
本质是相当于把所有源代码都编译到当前main里面了, main里面通过目录名和package包名来调用。
package mainimport ("fmt""test/util")func main(){info := util.Info{15}fmt.Println(info.Age)fmt.Println(util.Greeting())fmt.Println(util.Greeting2())fmt.Println(util.Return2(info))fmt.Println(util.Return(info))}
util/info.go
package utiltype Info struct{Age int}
util/util.go
package utilfunc Greeting()string{return "world hello "}func Return(info Info) int {return info.Age * 2}
util/util2.go
package utilfunc Greeting2()string{return "world hello 2"}func Return2(info Info) int {return info.Age+2}
// A Handler responds to an HTTP request.//// ServeHTTP should write reply headers and data to the ResponseWriter// and then return. Returning signals that the request is finished; it// is not valid to use the ResponseWriter or read from the// Request.Body after or concurrently with the completion of the// ServeHTTP call.//// Depending on the HTTP client software, HTTP protocol version, and// any intermediaries between the client and the Go server, it may not// be possible to read from the Request.Body after writing to the// ResponseWriter. Cautious handlers should read the Request.Body// first, and then reply.//// Except for reading the body, handlers should not modify the// provided Request.//// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes// that the effect of the panic was isolated to the active request.// It recovers the panic, logs a stack trace to the server error log,// and either closes the network connection or sends an HTTP/2// RST_STREAM, depending on the HTTP protocol. To abort a handler so// the client sees an interrupted response but the server doesn't log// an error, panic with the value ErrAbortHandler.type Handler interface {ServeHTTP(ResponseWriter, *Request)}
package mainimport ("fmt""log""net/http")func main() {// associate URLs requested to functions that handle requestshttp.Handle("/hello/lanre", &HelloWorld{"Lanre"})http.Handle("/hello/doe", &HelloWorld{"John doe"})//http.HandleFunc("/", getRequest)// start web serverlog.Fatal(http.ListenAndServe(":9999", nil))}type HelloWorld struct {Name string}func (h *HelloWorld) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, "Hello "+h.Name)}
curl http://localhost:9999/hello/dos
package mainimport ("encoding/json""fmt""strconv""net/http")type user struct {ID int `json:"id"`Moniker string `json:"moniker"`Bio string `json:"bio"`Languages []string `json:"languages`}var allUsers []*userfunc init() {allUsers = []*user{{ID: 1, Moniker: "Hades", Bio: "god of the underworld, ruler of the dead and brother to the supreme ruler of the gods, Zeus", Languages: []string{"Greek"}},{ID: 2, Moniker: "Horus", Bio: "god of the sun, sky and war", Languages: []string{"Arabic"}},{ID: 3, Moniker: "Apollo", Bio: "god of light, music, manly beauty, dance, prophecy, medicine, poetry and almost every other thing. Son of Zeus", Languages: []string{"Greek"}},{ID: 4, Moniker: "Artemis", Bio: "goddess of the wilderness and wild animals. Sister to Apollo and daughter of Zeus", Languages: []string{"Greek"}},}}func main() {http.Handle("/users/", users{})http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK)fmt.Fprintf(w, "You just reached the page of our startup. Thank you for visiting")})http.ListenAndServe(":4000", nil)}type users struct {}func (u users) ServeHTTP(w http.ResponseWriter, r *http.Request) {s := r.URL.Path[len("/users/"):]if s != "" {id, _ := strconv.Atoi(s)var requestedUser *uservar found boolfor _, v := range allUsers {if v.ID == id {found = true //god existsrequestedUser = vbreak}}if found {w.WriteHeader(http.StatusOK)j, _ := json.Marshal(&requestedUser)fmt.Fprintf(w, string(j))return}w.WriteHeader(http.StatusNotFound)return}//No id was specified so we return the defaultw.WriteHeader(http.StatusOK)j, _ := json.Marshal(allUsers)fmt.Fprintf(w, string(j))}
curl -X GET http://localhost:4000/users/3curl -X GET http://localhost:4000/users
https://gobyexample.com/http-servers
package mainimport ("fmt""net/http")func hello(w http.ResponseWriter, req *http.Request) {fmt.Fprintf(w, "hello\n")}func headers(w http.ResponseWriter, req *http.Request) {for name, headers := range req.Header {for _, h := range headers {fmt.Fprintf(w, "%v: %v\n", name, h)}}}func main() {http.HandleFunc("/hello", hello)http.HandleFunc("/headers", headers)http.ListenAndServe(":8090", nil)}
go get -u github.com/gorilla/mux
package mainimport ("fmt""log""net/http""github.com/gorilla/mux")func homeLink(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Welcome home!")}func main() {router := mux.NewRouter().StrictSlash(true)router.HandleFunc("/", homeLink)log.Fatal(http.ListenAndServe(":8190", router))}
package mainimport ("fmt""time")func numbers() {for i := 1; i <= 5; i++ {time.Sleep(250 * time.Millisecond)fmt.Printf("%d ", i)}}func alphabets() {for i := 'a'; i <= 'e'; i++ {time.Sleep(400 * time.Millisecond)fmt.Printf("%c ", i)}}func main() {go numbers()go alphabets()time.Sleep(3000 * time.Millisecond)fmt.Println("main terminated")}
1 a 2 3 b 4 c 5 d e main terminated
https://studygolang.com/articles/12342
第一张蓝色的图表示 numbers 协程,第二张褐红色的图表示 alphabets 协程,第三张绿色的图表示 Go 主协程,而最后一张黑色的图把以上三种协程合并了,表明程序是如何运行的。在每个方框顶部,诸如 0 ms 和 250 ms 这样的字符串表示时间(以微秒为单位)。在每个方框的底部,1、2、3 等表示输出。蓝色方框表示:250 ms 打印出 1,500 ms 打印出 2,依此类推。最后黑色方框的底部的值会是 1 a 2 3 b 4 c 5 d e main terminated,这同样也是整个程序的输出。以上图片非常直观,你可以用它来理解程序是如何运作的。
使用信道需要考虑的一个重点是死锁。当 Go 协程给一个信道发送数据时,照理说会有其他 Go 协程来接收数据。如果没有的话,程序就会在运行时触发 panic,形成死锁。
同理,当有 Go 协程等着从一个信道接收数据时,我们期望其他的 Go 协程会向该信道写入数据,要不然程序就会触发 panic。
package mainfunc main() {ch := make(chan int)ch <- 5}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox249677995/main.go:6 +0x80
数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。
当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。
v, ok := <- ch
package mainimport ("fmt")func producer(chnl chan int) {for i := 0; i < 10; i++ {chnl <- i}close(chnl)}func main() {ch := make(chan int)go producer(ch)for { // 无限的 for 循环v, ok := <-chif ok == false {break}fmt.Println("Received ", v, ok)}}
for range 循环用于在一个信道关闭之前,从信道接收数据。
接下来我们使用 for range 循环重写上面的代码。
package mainimport ("fmt")func producer(chnl chan int) {for i := 0; i < 10; i++ {chnl <- i}close(chnl)}func main() {ch := make(chan int)go producer(ch)for v := range ch {fmt.Println("Received ",v)}}
在第 16 行,for range 循环从信道 ch 接收数据,直到该信道关闭。一旦关闭了 ch,循环会自动结束。
无缓冲信道的发送和接收过程是阻塞的。
我们还可以创建一个有缓冲(Buffer)的信道。只在缓冲已满的情况,才会阻塞向缓冲信道(Buffered Channel)发送数据。同样,只有在缓冲为空的时候,才会阻塞从缓冲信道接收数据。
func write(ch chan int) {for i := 0; i < 5; i++ {ch <- ifmt.Println("successfully wrote", i, "to ch")}close(ch)}func main() {ch := make(chan int, 2)go write(ch)time.Sleep(2 * time.Second)for v := range ch {fmt.Println("read value", v,"from ch")time.Sleep(2 * time.Second)}}
说明: 对于 有容量的ch 信道, 可以采用 for v:= range ch的 循环来读取。直到 ch关闭。
若用 for range 接收数据时,对于关闭了的信道,会接收完剩下的有效数据,并退出循环。如果没有 close 提示数据发送完毕的话,for range 会接收完剩下所有有效数据后发生阻塞。
WaitGroup 用于实现工作池,因此要理解工作池,我们首先需要学习 WaitGroup。
WaitGroup 用于等待一批 Go 协程执行结束。程序控制会一直阻塞,直到这些协程全部执行完毕。假设我们有 3 个并发执行的 Go 协程(由 Go 主协程生成)。Go 主协程需要等待这 3 个协程执行结束后,才会终止。这就可以用 WaitGroup 来实现。
package mainimport ("fmt""sync""time")func process(i int, wg *sync.WaitGroup) {fmt.Println("started Goroutine ", i)time.Sleep(2 * time.Second)fmt.Printf("Goroutine %d ended\n", i)wg.Done()}func main() {no := 3var wg sync.WaitGroupfor i := 0; i < no; i++ {wg.Add(1)go process(i, &wg)}wg.Wait()fmt.Println("All go routines finished executing")}
var wg sync.WaitGroup
wg.Add() // 添加计数,需要
wg.Done() // 完成的进程
wg.Wait() // 等待所有完成。
注意: &wg ,
Visually Understanding Worker Pool
https://medium.com/coinmonks/visually-understanding-worker-pool-48a83b7fc1f5
select 语句用于在多个发送/接收信道操作中进行选择。select 语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select 会随机地选取其中之一执行。该语法与 switch 类似,所不同的是,这里的每个 case 语句都是信道操作。我们好好看一些代码来加深理解吧。
output1 := make(chan string)output2 := make(chan string)go server1(output1)go server2(output2)select {case s1 := <-output1:fmt.Println(s1)case s2 := <-output2:fmt.Println(s2)}
在学习 Mutex 之前,我们需要理解并发编程中临界区(Critical Section)的概念。当程序并发地运行时,多个 Go 协程不应该同时访问那些修改共享资源的代码 (例如: x = x +1 )
根据上下文切换的不同情形,x 的最终值是 1 或者 2。这种不太理想的情况称为竞态条件(Race Condition),其程序的输出是由协程的执行顺序决定的。
如果在任意时刻只允许一个 Go 协程访问临界区,那么就可以避免竞态条件。而使用 Mutex 可以达到这个目的。
Mutex 用于提供一种加锁机制(Locking Mechanism),可确保在某时刻只有一个协程在临界区运行,以防止出现竞态条件。
mutex.Lock()x = x + 1mutex.Unlock()
总体说来,当 Go 协程需要与其他协程通信时,可以使用信道。而当只允许一个协程访问临界区时,可以使用 Mutex。
https://blog.golang.org/json-and-go
推荐:
https://yourbasic.org/golang/json-example/
// json.go
package mainimport ("encoding/json""fmt""net/http")type User struct {Firstname string `json:"firstname"`Lastname string `json:"lastname"`Age int `json:"age"`}func main() {http.HandleFunc("/decode", func(w http.ResponseWriter, r *http.Request) {var user Userjson.NewDecoder(r.Body).Decode(&user)fmt.Fprintf(w, "%s %s is %d years old!", user.Firstname, user.Lastname, user.Age)})http.HandleFunc("/encode", func(w http.ResponseWriter, r *http.Request) {peter := User{Firstname: "John",Lastname: "Doe",Age: 25,}json.NewEncoder(w).Encode(peter)})http.ListenAndServe(":8080", nil)}
run:
$ go run json.go$ curl -s -XPOST -d'{"firstname":"Elon","lastname":"Musk","age":48}' http://localhost:8080/decodeElon Musk is 48 years old!$ curl -s http://localhost:8080/encode{"firstname":"John","lastname":"Doe","age":25}
package mainimport ("encoding/json""fmt")// Employee struct with struct tagstype Employee struct {ID int `json:"id,omitempty"`FirstName string `json:"firstname"`LastName string `json:"lastname"`JobTitle string `json:"job"`}func main() {emp := Employee{FirstName: "Shiju",LastName: "Varghese",JobTitle: "Architect",}// Encoding to JSONdata, err := json.Marshal(emp)if err != nil {fmt.Println(err.Error())return}jsonStr := string(data)fmt.Println("The JSON data is:")fmt.Println(jsonStr)b := []byte(`{"id":101,"firstname":"Irene","lastname":"Rose","job":"Developer"}`)var emp1 Employee// Decoding JSON to a struct typeerr = json.Unmarshal(b, &emp1)if err != nil {fmt.Println(err.Error())return}fmt.Println("The Employee value is:")fmt.Printf("ID:%d, Name:%s %s, JobTitle:%s", emp1.ID, emp1.FirstName, emp1.LastName,emp1.JobTitle)}
output:
The JSON data is:{"firstname":"Shiju","lastname":"Varghese","job":"Architect"}The Employee value is:ID:101, Name:Irene Rose, JobTitle:Developer
package mainimport ("encoding/json""fmt""os")func main() {type ColorGroup struct {ID intName stringColors []string}group := ColorGroup{ID: 1,Name: "Reds",Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},}b, err := json.Marshal(group)if err != nil {fmt.Println("error:", err)}os.Stdout.Write(b)}
package mainimport ("encoding/json""fmt""os")type response1 struct {Page intFruits []string}type response2 struct {Page int `json:"page"`Fruits []string `json:"fruits"`}func main() {bolB, _ := json.Marshal(true)fmt.Println(string(bolB))intB, _ := json.Marshal(1)fmt.Println(string(intB))fltB, _ := json.Marshal(2.34)fmt.Println(string(fltB))strB, _ := json.Marshal("gopher")fmt.Println(string(strB))slcD := []string{"apple", "peach", "pear"}slcB, _ := json.Marshal(slcD)fmt.Println(string(slcB))mapD := map[string]int{"apple": 5, "lettuce": 7}mapB, _ := json.Marshal(mapD)fmt.Println(string(mapB))res1D := &response1{Page: 1,Fruits: []string{"apple", "peach", "pear"}}res1B, _ := json.Marshal(res1D)fmt.Println(string(res1B))res2D := &response2{Page: 1,Fruits: []string{"apple", "peach", "pear"}}res2B, _ := json.Marshal(res2D)fmt.Println(string(res2B))byt := []byte(`{"num":6.13,"strs":["a","b"]}`)var dat map[string]interface{}if err := json.Unmarshal(byt, &dat); err != nil {panic(err)}fmt.Println(dat)num := dat["num"].(float64)fmt.Println(num)strs := dat["strs"].([]interface{})str1 := strs[0].(string)fmt.Println(str1)str := `{"page": 1, "fruits": ["apple", "peach"]}`res := response2{}json.Unmarshal([]byte(str), &res)fmt.Println(res)fmt.Println(res.Fruits[0])enc := json.NewEncoder(os.Stdout)d := map[string]int{"apple": 5, "lettuce": 7}enc.Encode(d)}
output:
$ go run json.gotrue12.34"gopher"["apple","peach","pear"]{"apple":5,"lettuce":7}{"Page":1,"Fruits":["apple","peach","pear"]}{"page":1,"fruits":["apple","peach","pear"]}map[num:6.13 strs:[a b]]6.13a{1 [apple peach]}apple{"apple":5,"lettuce":7}
package mainimport ("encoding/json""errors""fmt""io/ioutil""log""os""github.com/tidwall/gjson""github.com/tidwall/pretty""github.com/tidwall/sjson")const jsons = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`func main() {jsons, _ := sjson.Set(jsons, "name.last", "Anderson")jsons, _ = sjson.Set(jsons, "work", "IT manager")println(jsons)bjson := pretty.Pretty([]byte(jsons))println(string(bjson))ioutil.WriteFile("p_marhsall.json", bjson, os.ModePerm)/*jsonstr, _ := getjsonstr("p_marhsall.json")fmt.Println(gjson.Get(jsonstr, "work").String())*/}
https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html
go
package main// https://blog.kowalczyk.info/article/wOYk/advanced-command-execution-in-go-with-osexec.html// to run:// go run 01-simple-exec.goimport ("fmt""log""os/exec""runtime")func main() {cmd := exec.Command("ls", "-lah")if runtime.GOOS == "windows" {cmd = exec.Command("tasklist")}out, err := cmd.CombinedOutput()if err != nil {log.Fatalf("cmd.Run() failed with %s\n", err)}fmt.Printf("combined out:\n%s\n", string(out))}
package mainimport ("fmt""log""os/exec")func main() {cmd := exec.Command("program") // or whatever the program iscmd.Dir = "C:/usr/bin" // or whatever directory it's inout, err := cmd.Output()if err != nil {log.Fatal(err)} else {fmt.Printf("%s", out);}}