Goroutines

Go 語言中的併發能夠用兩種方式實現:編程

  • 第一種方式,支持順序通訊進程(communicating sequential processes),簡稱 CSP。CSP是一種現代的併發編程模型,在這種編程模型中值會在不一樣的運行實例(goroutine)中傳遞,儘管大多數狀況下仍然是被限制在單一實例中。服務器

  • 第二種實現方式就是更爲傳統的併發模型:多線程共享內存。網絡

在Go語言中,每個併發的執行單元叫做一個goroutine。當一個程序啓動時,其主函數即在一個單獨的goroutine中運行,咱們叫它main goroutine。新的goroutine會用go語句來建立。在語法上,go語句是一個普通的函數或方法調用前加上關鍵字go。go語句會使其語句中的函數在一個新建立的goroutine中運行。而go語句自己會迅速地完成。主goroutine 結束運行,則 後臺goroutine結束執行。多線程

示例1併發

主 goroutine和後臺goroutinetcp

func main() {
       go spinner(100 * time.Millisecond)
       const n = 45
       fibN := fib(n) // slow
       fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)
}

//旋轉的動畫
func spinner(delay time.Duration) {
       for {
              for _, r := range `-\|/` {
                     fmt.Printf("\r%c", r)
                     time.Sleep(delay)
              }
       }
}

//菲波那契數列
func fib(x int) int {
       if x < 2 {
              return x
       }
       return fib(x-1) + fib(x-2)
}

示例2函數

下面的例子是順序執行的時鐘服務器,它會每隔一秒鐘將當前時間寫到客戶端動畫

package main

import (
	"log"
	"net"
	"time"
	"io"
)

func main() {
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err) // e.g., connection aborted
			continue
		}
		handleConn(conn) // handle one connection at a time
	}
}

func handleConn(c net.Conn) {
	defer c.Close()
	for {
		_, err := io.WriteString(c, time.Now().Format("15:04:05\n"))
		if err != nil {
			return // e.g., client disconnected
		}
		time.Sleep(1 * time.Second)
	}
}

 

分析:線程

net.Listen函數建立了一個net.Listener的對象,這個對象會監聽一個網絡端口上到來的鏈接,在這個例子裏咱們用的是TCP的localhost:8000端口。listener對象的Accept方法會直接阻塞,直到一個新的鏈接被建立,而後會返回一個net.Conn對象來表示這個鏈接。orm

 

能夠使用 netcat命令鏈接這個服務。

 

 

 

 

 

 

或者使用 net.Dial() 來鏈接這個服務

// This is a read-only TCP client.
package main

import (
	"io"
	"log"
	"net"
	"os"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	mustCopy(os.Stdout, conn)
}

func mustCopy(dst io.Writer, src io.Reader) {
	if _, err := io.Copy(dst, src); err != nil {
		log.Fatal(err)
	}
}

net.Dial() 撥號,返回一個鏈接。從鏈接中獲取數據打印到輸出流。

 

併發分析:

上面的服務端同時只能處理一個客戶端鏈接,客戶端必須等服務端完成工做才執行。爲了支持併發,在handleConn函數調用的地方增長go關鍵字,讓每一次handleConn的調用都進入一個獨立的goroutine。

 

示例3

併發的 echo服務。在單個鏈接中創建多個 goroutine

相關文章
相關標籤/搜索