
Go并发基础与Goroutine
go语言以其内置的并发原语而闻名,其中goroutine是其核心。goroutine是一种轻量级的执行线程,由go运行时管理。通过在函数调用前加上go关键字,即可将其作为一个新的goroutine并发执行,而无需像传统线程那样承担高昂的创建和销毁开销。这种设计使得go程序能够轻松地利用多核处理器,提高程序的响应性和吞吐量。
当一个Goroutine被启动时,它会与主Goroutine以及其他已存在的Goroutine并行或并发地执行(取决于可用的CPU核心数量和调度器的安排)。这意味着多个Goroutine可以同时进行工作,互不干扰,除非它们需要共享资源并进行同步。
time.Sleep函数的作用机制
time.Sleep(d Duration)函数的作用是暂停当前正在执行的Goroutine,使其休眠指定的持续时间d。重要的是要理解,time.Sleep只影响调用它的那个Goroutine,而不会暂停整个程序或其他的Goroutine。Go调度器会在当前Goroutine休眠期间,将CPU资源分配给其他可运行的Goroutine。
深入解析并发time.Sleep行为
考虑以下Go代码片段,它展示了在多个Goroutine中调用time.Sleep时的行为:
package main
import (
"fmt"
"strconv"
"time"
)
// getHostName 模拟一个耗时操作,其中包含time.Sleep
func getHostName(h chan string, ipAdresse string, n int) {
// Goroutine在此处暂停4秒
time.Sleep(4 * time.Second)
ip := ipAdresse + strconv.Itoa(n)
// 模拟一些逻辑,然后将结果发送到通道
if false { // 示例中始终为false,模拟错误情况
h <- ip + " - "
} else {
h <- "error" + strconv.Itoa(n)
}
}
func main() {
max := 5 // 启动5个Goroutine
haveHost := make(chan string, max)
ipadresse_3 := "192.168.178."
fmt.Println("启动Goroutine...")
// 循环启动多个Goroutine
for i := 0; i < max; i++ {
go getHostName(haveHost, ipadresse_3, i)
}
// 从通道接收结果
for i := 0; i < max; i++ {
result := <-haveHost
fmt.Printf("收到结果: %s (在 %v)\n", result, time.Now().Format("15:04:05"))
}
fmt.Println("所有Goroutine完成。")
}在上述示例中,main函数通过一个for循环启动了max个getHostName Goroutine。每个getHostName函数内部都包含time.Sleep(4 * time.Second)。
本文档主要讲述的是用Apache Spark进行大数据处理——第一部分:入门介绍;Apache Spark是一个围绕速度、易用性和复杂分析构建的大数据处理框架。最初在2009年由加州大学伯克利分校的AMPLab开发,并于2010年成为Apache的开源项目之一。 在这个Apache Spark文章系列的第一部分中,我们将了解到什么是Spark,它与典型的MapReduce解决方案的比较以及它如何为大数据处理提供了一套完整的工具。希望本文档会给有需要的朋友带来帮助;感
行为分析:
- 并发启动: 当for循环执行go getHostName(...)时,它会迅速地启动max个独立的Goroutine。这些Goroutine几乎是同时开始执行的。
- 独立休眠: 每个Goroutine一旦启动,就会执行到time.Sleep(4 * time.Second)这一行。此时,每个Goroutine都会独立地进入休眠状态,暂停自身4秒。
- 同时唤醒: 由于所有Goroutine几乎同时开始休眠,它们也会在大致相同的时间点(即大约4秒后)被唤醒。
- 同时完成: 唤醒后,每个Goroutine继续执行剩余的代码,并将结果发送到haveHost通道。因为它们几乎同时唤醒,所以main Goroutine也会在短时间内连续接收到所有结果。
因此,观察到的现象是,程序似乎在等待了4秒后,所有的结果才几乎同时出现,而不是每个Goroutine依次等待4秒。这正是Go并发的预期行为:time.Sleep作用于单个Goroutine,而多个Goroutine是并发运行的。
关键概念与注意事项
- Goroutine的独立性: 每个Goroutine都有其独立的执行栈,time.Sleep只会暂停调用它的那个栈,不会影响其他并发运行的Goroutine。
- 调度器的工作: 当一个Goroutine进入休眠状态时,Go调度器会将其从运行队列中移除,并安排其他可运行的Goroutine来使用CPU。休眠结束后,该Goroutine会被重新放入运行队列等待调度。
- 并发与并行: 在多核处理器上,Go调度器可以真正地并行运行多个Goroutine。即使在单核处理器上,Go调度器也能通过快速切换Goroutine来实现并发(伪并行),使得它们看起来像是在同时运行。
- 避免误解: 初学者可能会误以为time.Sleep会暂停整个程序,或者会使Goroutine串行执行。理解其作用于单个Goroutine的特性是掌握Go并发的关键。
总结
time.Sleep函数在Go语言中是用于暂停单个Goroutine执行的。当多个Goroutine被并发启动,并且每个Goroutine内部都调用了time.Sleep时,它们会各自独立地进入休眠状态,并在指定时间后几乎同时被唤醒并完成后续操作。这种行为是Go语言并发模型的核心体现,即Goroutine是轻量级且高度独立的执行单元。正确理解这一机制对于编写高效、可维护的Go并发程序至关重要。









