1. 前言
在编程领域,多线程一直都是一个重要的话题。作为一门现代化的编程语言,Golang也有着强大的并发编程能力。在这篇文章里,我们将会探索Golang中的并发编程,特别是Goroutine的使用。
2. 什么是Goroutine?
Goroutine是Golang内置的轻量级线程。相比传统的线程,Goroutine更加高效和灵活。在Golang中,我们可以轻易地启动一个Goroutine,并且可以同时启动多个。
3. Goroutine的使用
3.1 启动一个Goroutine
在Golang中,我们可以使用内置的go关键字来启动一个Goroutine:
go func(){
// 这里是要执行的代码
}()
上面这段代码就启动了一个Goroutine。其中,func()表示一个匿名函数,这个函数将会在Goroutine中执行。在匿名函数的最后,我们加了一堆括号,这是为了让这个匿名函数立即执行,也就是启动这个Goroutine。
同时,我们也可以把Goroutine启动和函数定义分离开来,这样代码会更加清晰:
func myFunc(){
// 这里是要执行的代码
}
go myFunc()
这样,我们就成功地启动了一个Goroutine,并且使得myFunc函数在Goroutine中执行。
3.2 Goroutine的传参
在Golang中,我们可以使用闭包来让Goroutine获取外部变量的值:
func myFunc(str string){
// 这里是要执行的代码
}
go myFunc("Hello, World!")
我们在启动Goroutine时把字符串"Hello, World!"作为参数传给了myFunc函数。这个参数在Goroutine中可以被myFunc获取到,并且在myFunc中使用。
3.3 Goroutine的并发
在Golang中,我们可以同时启动多个Goroutine,让它们并发地执行。同时,我们也可以使用Golang的channel来控制Goroutine的并发执行。
下面是一个简单的例子,展示如何创建多个Goroutine并发执行,并且使用channel在它们之间传递数据:
func myFunc(name string, c chan string){
for i:=0; i<3; i++ {
// 使用channel发送数据
c <- "Hello from " + name + "!"
// 等待一段时间
time.Sleep(time.Millisecond * 100)
}
}
func main() {
// 创建一个channel
c := make(chan string)
// 使用多个Goroutine并发地执行myFunc
go myFunc("Alice", c)
go myFunc("Bob", c)
// 接收并打印myFunc传回的数据
for i:=0; i<6; i++ {
fmt.Println(<-c)
}
}
在上面的例子中,我们创建了两个Goroutine,并且使用channel在它们之间传递数据。我们使用了time.Sleep函数来模拟Goroutine中的一些耗时操作。
4. 让我们来写一个小应用吧!
在这个小应用中,我们要实现下面这个功能:我们有一个切片,里面有很多数字。我们希望把这些数字加上一个固定值,并且输出加完后的结果。
4.1 串行计算
首先,我们来看一下基本的串行计算方式:
func addNumbers(nums []int, numToAdd int) []int {
for i := 0; i < len(nums); i++ {
nums[i] += numToAdd
}
return nums
}
func main() {
nums := []int{1, 2, 3, 4, 5}
nums = addNumbers(nums, 10)
fmt.Println(nums)
}
上面这段代码中,我们定义了一个addNumbers函数,这个函数接收一个切片和一个需要加的数字。函数内部遍历切片,把切片中的每个数字都加上需要加的数字,并返回修改后的切片。在main函数中,我们创建了一个初始切片,传给addNumbers函数进行加法操作,并且输出了最终结果。
4.2 并行计算
现在,我们来尝试使用Go来进行并行计算。我们将会使用Goroutine来启动多个并发的任务,让它们同时对切片中的数字进行加法操作。
func addNumbers(nums []int, numToAdd int, c chan []int) {
for i := 0; i < len(nums); i++ {
nums[i] += numToAdd
}
// 使用channel传递修改后的切片
c <- nums
}
func main() {
nums := []int{1, 2, 3, 4, 5}
c := make(chan []int)
// 启动4个Goroutine并发计算
for i := 0; i < 4; i++ {
go addNumbers(nums, 10, c)
}
// 收集所有结果
var finalNums []int
for i := 0; i < 4; i++ {
finalNums = <-c
}
fmt.Println(finalNums)
}
在上面的代码中,我们定义了一个新的addNumbers函数,并且传入了一个channel,这个channel用于传递计算结果。在main函数中,我们创建了一个channel,用于传递所有Goroutine的计算结果。
我们使用一个for循环分别启动了4个Goroutine,并且让它们计算原始切片的副本。每个Goroutine计算完之后,它们会把计算结果传入channel中。在main函数中,我们再次使用一个for循环,把所有的计算结果从channel中取出,合并到一个新的切片中,并且输出最终结果。
5. 总结
在本文中,我们探讨了Golang中并发编程的基础知识,并且使用一个小应用演示了并发计算的实现。除此之外,Golang的并发编程还有很多高级用法,例如mutex、atomic和select等。希望读者能够继续深入学习Golang的并发编程,掌握更多的技巧和技术。