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

相关文章
相关标签/搜索