1、Goroutines是轻量级线程

go语句在单独的线程中运行一个函数。

你可以使用go语句启动一个新的执行线程,即一个goroutine。它在一个不同的,新创建的goroutine中运行一个函数。 单个程序中的所有goroutine共享相同的地址空间。

go list.Sort() // Run list.Sort in parallel; don’t wait for it.

以下程序将打印“Hello from main goroutine”。它也可能打印出“来自另一个goroutine的Hello”,这取决于两个goroutine中的哪一个先完成。

func main() {
go fmt.Println("Hello from another goroutine")
fmt.Println("Hello from main goroutine") // At this point the program execution stops and all
// active goroutines are killed.
}

下一个程序很可能会打印“Hello from main goroutine”和“Hello from another goroutine”。 它们可以按任何顺序打印。 另一种可能性是第二个goroutine非常慢并且在程序结束之前不打印它的消息。

func main() {
go fmt.Println("Hello from another goroutine")
fmt.Println("Hello from main goroutine") time.Sleep(time.Second) // give the other goroutine time to finish
}

这是一个更直接的例子,我们定义一个使用并发来推迟事件的函数。

// Publish prints text to stdout after the given time has expired.
// It doesn’t block but returns right away.
func Publish(text string, delay time.Duration) {
go func() {
time.Sleep(delay)
fmt.Println("BREAKING NEWS:", text)
}() // Note the parentheses. We must call the anonymous function.
}

下面是Publish函数的使用示例

func main() {
Publish("A goroutine starts a new thread.", 5*time.Second)
fmt.Println("Let’s hope the news will published before I leave.") // Wait for the news to be published.
time.Sleep(10 * time.Second) fmt.Println("Ten seconds later: I’m leaving now.")
}

该程序很可能以给定的顺序打印以下三行,每行之间有五秒钟的间隔。

$ go run publish1.go
Let’s hope the news will published before I leave.
BREAKING NEWS: A goroutine starts a new thread.
Ten seconds later: I’m leaving now.

通常,不可能通过sleep来安排线程等待彼此。 Go的主要同步方法是使用channels。

Goroutines是轻量级的。会导致较小的栈增长,主要通过根据需要分配和释放堆存储。内部goroutines就像在多个操作系统线程之间复用的协程一样。如果一个goroutine被阻塞,例如等待输入,则此线程中的其他goroutine将迁移,以便它们可以继续运行。

2、channels的同步通信

channel是goroutine通过传递值来同步执行和通信的机制。

// unbuffered channel of ints
ic := make(chan int) // buffered channel with room for 10 strings
sc := make(chan string, 10)

要在channel上发送值,请使用<-作为二元运算符。要在channel上接收值,请将其用作一元运算符。

ic <- 3   // Send 3 on the channel.
n := <-sc // Receive a string from the channel.

<- 运算符指定channel方向,发送或接收。如果没有给出方向,则通道是双向的。

chan Sushi    // can be used to send and receive values of type Sushi
chan<- string // can only be used to send strings
<-chan int // can only be used to receive ints
  • 缓冲和无缓冲channel

    1. 如果channel的容量为零或不存在,则channel是无缓冲的,发送方将阻塞,直到接收方收到该值。
    2. 如果channel有缓冲区,则发送方仅阻塞,直到将值复制到缓冲区为止; 如果缓冲区已满,则表示等待某个接收方检索到某个值。
    3. 接收方始终阻塞,直到有数据要接收。
    4. 从nil channel发送或接收将永久阻塞。
  • 关闭channel

close函数调用后标志将不再在channel上发送值。请注意,只有在接收方期望关闭时才需要关闭channel。

1. 在调用close之后,在收到任何先前发送的值之后,接收操作将返回零值而不会阻塞。

2. 多值接收操作另外返回channel是否关闭的标识。

3. 发送或关闭已关闭的channel会导致运行时出现panic。关闭nil channel也会导致运行时panic。

ch := make(chan string)
go func() {
ch <- "Hello!"
close(ch)
}() fmt.Println(<-ch) // Print "Hello!".
fmt.Println(<-ch) // Print the zero value "" without blocking.
fmt.Println(<-ch) // Once again print "".
v, ok := <-ch // v is "", ok is false. // Receive values from ch until closed.
for v := range ch {
fmt.Println(v) // Will not be executed.
}

在下面的示例中,我们让Publish函数返回一个channel,该channel用于在文本发布时广播消息。

// Publish prints text to stdout after the given time has expired.
// It closes the wait channel when the text has been published.
func Publish(text string, delay time.Duration) (wait <-chan struct{}) {
ch := make(chan struct{})
go func() {
time.Sleep(delay)
fmt.Println(text)
close(ch)
}()
return ch
}

请注意,我们使用空结构channel来指示channel仅用于通信,而不是用于传递数据。 下面是使用该函数例子。

wait := Publish("important news", 2 * time.Minute)
// Do some more work.
<-wait // Block until the text has been published.

最新文章

  1. MySQL学习笔记六:基本DML操作
  2. C# iis 错误配置信息( CS0016: 未能写入输出文件 )
  3. C++ 构造与析构函数
  4. iOS开发之网络编程--2、NSURLSessionDownloadTask文件下载
  5. github 建立博客
  6. 经典ASP.NET MVC3.0入门详解
  7. String Reduction
  8. xHtml+css学习笔记
  9. healthkit 记录每天用户的运动情况
  10. php函数的种类与调用方法大揭密
  11. SQLite新建数据库及txt文件(CSV文件)导入
  12. linux服务器文件授权命令
  13. VS的工作目录和输出目录
  14. BZOJ4963 : String
  15. 安装httpd服务
  16. sql 表连接
  17. 笔记-返回到前一个页面时显示前一个页面中ajax获取的数据
  18. 《剑指offer》-中序遍历下一个节点
  19. kubeadm 生成的token过期后,集群增加节点
  20. 二:nodejs+express+redis+bootstrap table+jquery UI

热门文章

  1. 46 Linden Street ACT I
  2. Vue基础系列(二)——Vue中的methods属性
  3. [高效工作软件] Capslock+的使用笔记 (快捷键)
  4. hdu 1263 水果 (嵌套 map)
  5. 简单的 smartpointer
  6. Android DecorView 与 Activity 绑定原理分析
  7. template screen
  8. AE ArcEngine10.4+vs2012安装配置
  9. cognos服务器性能测试诊断分析优化过程记录
  10. 【计算机网络】你真的了解HTTP(HTTPS)协议的这12个知识点吗