一、常见题目
1.1 三个协程交替打印ABC
建立三个线程A、B、C,A线程打印10次字母A,B线程打印10次字母B,C线程打印10次字母C,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印。
package main
import(
"fmt"
"sync"
)
var wg sync.WaitGroup
var ch1, ch2, ch3 = make(chan int), make(chan int), make(chan int)
func print_A(){
defer wg.Done()
for i := 0; i < 10; i++ {
<- ch1
fmt.Print("A")
ch2 <- 1
}
<- ch1
}
func print_B(){
defer wg.Done()
for i := 0; i < 10; i++{
// a.Done()
// fmt.Print("B")
// b.Add(1)
<- ch2
fmt.Print("B")
ch3 <- 1
}
}
func print_C(){
// print_C运行结束wg再-1
defer wg.Done()
for i := 0; i < 10; i++{
<- ch3
fmt.Print("C")
ch1 <- 1
}
}
// 建立三个线程A、B、C,A线程打印10次字母A,B线程打印10次字母B,C线程打印10次字母C,
// 但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印。
func main(){
// wg确保main函数在所有协程运行完毕再退出
wg.Add(3)
go print_A()
go print_B()
go print_C()
// 确保所有 goroutine 都已经启动并准备好接收信号,然后再发送第一个信号。这样可以避免在开始时出现竞争条件或死锁。
ch1 <- 1
wg.Wait()
fmt.Println(" Done")
}
1.2 并发访问多个URL,存储状态信息
package main
import (
"fmt"
"net/http"
"sync"
)
// fetchURL 发送 HTTP GET 请求并返回响应状态码,如果请求出错则返回错误信息。
func fetchURL(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", err
}
defer resp.Body.Close()
// fmt.Printf("Fetched %s with status: %s\n", url, resp.Status) // 调试输出
return resp.Status, nil
}
func main() {
urls := []string{
"https://www.zijie.com",
"https://www.baidu.com",
"https://www.alibaba.com",
// 添加更多的 URL...
}
results := make(chan string)
var wg sync.WaitGroup
// 启动 goroutine 发送 HTTP 请求
for _, url := range urls {
// _:0,1,2
wg.Add(1) // 每个 goroutine 开始前增加 WaitGroup 的计数器
go func(url string) {
defer wg.Done()
data, err := fetchURL(url)
if err != nil {
fmt.Println("Error fetching", url, ":", err)
return
}
// data写给管道
results <- data
// url作为参数
}(url)
}
// 启动一个 goroutine 等待所有任务完成后关闭通道
go func() {
wg.Wait() // 等待所有 goroutine 完成
close(results) // 当所有请求处理完毕后关闭通道,告知 range 循环停止
}()
// 从通道中读取并处理每个 URL 请求的响应状态码
for result := range results {
// 这里可以将获取到的数据进行处理,例如打印或保存到文件中
fmt.Println(result)
}
}
1.3 生成随机数并且计算各个位数之和再打印
// 使用 goroutine 和 channel 实现一个计算int64随机数各位数和的程序,例如生成随机数61345,计算其每个位数上的数字之和为19。
// 1. 开启一个 goroutine 循环生成int64类型的随机数,发送到`jobChan`
// 2. 开启24个 goroutine 从`jobChan`中取出随机数计算各位数的和,将结果发送到`resultChan`
// 3. 主 goroutine 从`resultChan`取出结果并打印到终端输出
package main
import (
"fmt"
"math/rand"
"sync"
)
// ch1, ch2:= make(chan int),make(chan int)
func cal_num(n int64) int{
sum := 0
for n != 0{
sum += int(n%10)
n /= 10
}
// fmt.Println(n, "数字之和", sum)
return sum
}
func main(){
jobChan,resultChan:= make(chan int64),make(chan int)
var wg sync.WaitGroup
// 开启一个 goroutine 循环生成int64类型的随机数,发送到`jobChan`
go func () {
for{
randomNumber := rand.Int63()
jobChan <-randomNumber
}
}()
// 开启24个 goroutine 从`jobChan`中取出随机数计算各位数的和,将结果发送到`resultChan`
for i :=0;i<24;i++{
wg.Add(1)
go func () {
defer wg.Done()
for{
select{
case num:= <- jobChan:
sum := cal_num(num)
// fmt.Println(num, "数字之和", sum)
resultChan <- sum
}
}
}()
}
go func(){
for c:=range resultChan{
fmt.Println(c)
}
}()
wg.Wait() // 等待所有 goroutine 完成
}