go中并发编程利用goroutine(轻量级线程)和channel(通信管道)实现。goroutine通过go关键字创建,非常轻量,可创建大量goroutine,且不会影响性能。channel用于goroutine间通信,是类型化的管道。本例展示了并发爬虫的应用,使用goroutine并行爬取url,提高效率。
Go 核心技术解析:并发编程
Go 中的并发模型基于 goroutine(轻量级线程)和 channel(通信管道)的概念。通过充分利用这些特性,开发者可以构建高并发、高性能的应用程序。
Goroutine
Goroutine 是 Go 中的轻量级线程,由关键字 go
创建。它们在协程调度器上运行,与传统线程不同,goroutine 非常轻量,可以创建数千个而不会对性能造成重大影响。以下代码展示了如何创建和使用 goroutine:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("Number of goroutines: %dn", runtime.NumGoroutine()) // 当前正在运行的 goroutine 数量
// 创建一个 goroutine
go func() {
fmt.Println("Hello from a goroutine!")
}()
fmt.Printf("Number of goroutines: %dn", runtime.NumGoroutine()) // 当前正在运行的 goroutine 数量
}
Channel
Channel 是用于 goroutine 之间通信的管道。它们是类型化的,这意味着它们只能传递特定类型的值。以下代码展示了如何创建和使用 channel:
package main
import (
"fmt"
)
func main() {
// 创建一个 int 类型的 channel
c := make(chan int)
// 向 channel 发送值
go func() {
c <- 42
}()
// 从 channel 接收值
v := <-c
fmt.Println(v) // 输出:42
}
实战案例:并发爬虫
以下是一个使用 goroutine 和 channel 构建并发爬虫的简化示例:
package main
import (
"fmt"
"net/http"
"sync"
)
var wg sync.WaitGroup
func main() {
// 要爬取的 URL 列表
urls := []string{
"https://example.com",
"https://example2.com",
"https://example3.com",
}
// 创建 channel 来接收每个 URL 的响应
results := make(chan string)
// 为每个 URL 创建一个 goroutine
for _, url := range urls {
wg.Add(1)
go func(url string) {
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Error fetching %s: %vn", url, err)
} else if resp.StatusCode == 200 {
results <- url
}
wg.Done()
}(url)
}
// 从 channel 中获取响应
go func() {
for url := range results {
fmt.Println(url)
}
}()
// 等待所有 goroutine 完成
wg.Wait()
}
通过使用 goroutine 和 channel,此爬虫可以并发爬取多个 URL,从而提高了效率。