注意:WaitGroup对象不是一个引用类型,通过函数传值的时候需要使用地址,因为Go语言只有值传递,传递WaitGroup是值的话,就会导致会发生panic!!!
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
//goroutine 交替打印数字和字母
//打印数字
func NumberPrint(numCh chan int, letterCh chan int) {
i := 1
for {
<-numCh
fmt.Printf("%d", i)
i = i + 1
letterCh <- 1
}
}
func LetterPrint(numCh chan int, letterCh chan int) {
str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
i := 0
for {
<-letterCh
if i >= len(str) {
wg.Done()
return
}
fmt.Print(string(str[i]))
i = i + 1
numCh <- 1
}
}
func main() {
numCh, letterCh := make(chan int), make(chan int)
wg.Add(1)
go NumberPrint(numCh, letterCh)
go LetterPrint(numCh, letterCh)
letterCh <- 1 //重点!!!!,缺这句会导致死锁
wg.Wait()
}
一种更加优雅的写法
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
chNumber := make(chan struct{})
chLetter := make(chan struct{})
i := 0
index := 0
a := "abcdefghijklmnopqrskuvwxyz"
go func() {
for {
select {
case <-chNumber:
fmt.Print(i)
i++
chLetter <- struct{}{}
break
default:
break
}
}
}()
go func(wg *sync.WaitGroup) {
for {
select {
case <-chLetter:
if index > len(a)-1 {
wg.Done()
return
}
fmt.Print(string(a[index]))
index++
chNumber <- struct{}{}
break
default:
break
}
}
}(&wg)
chNumber <- struct{}{}
wg.Wait()
}
参考:http://beangogo.cn/2021/03/03/golang-%E4%BA%A4%E6%9B%BF%E6%89%93%E5%8D%B0/
package main
import "fmt"
// 10个协程交替打印数字1~100
func main() {
num := 100
numG := 10
chanArr := make([]chan int, numG)
for i := 0; i < numG; i++ {
chanArr[i] = make(chan int)
}
exit := make(chan bool)
for i := 0; i < numG; i++ {
go PrintNum(chanArr[i], chanArr[(i+1)%numG], num, i, exit)
}
chanArr[0] <- 0
<-exit
}
func PrintNum(nowChan, nextChan chan int, num, i int, exit chan bool) {
for {
currNum := <-nowChan
if currNum >= num {
exit <- true
break
}
currNum++
fmt.Println("协程:", i, "currNum:", currNum)
nextChan <- currNum
}
}
package main
import (
"fmt"
"time"
)
type Client struct {
name string
source chan interface{}
quit chan bool
}
func main() {
n := 3 //client的数量
clientCh := make([]*Client, n)
for i := 0; i < n; i++ {
clientCh[i] = &Client{
name: fmt.Sprintf("G-%d", i),
source: make(chan interface{}),
quit: make(chan bool),
}
}
for _, v := range clientCh {
go clientListen(v)
}
go hostSend(clientCh)
time.Sleep(time.Second * 5)
}
func clientListen(host *Client) {
//客户端接收通知
for {
select {
case msg := <-host.source:
fmt.Printf("client:%s 收听到消息:%s\n", host.name, msg)
case <-host.quit:
fmt.Printf("client:%s退出\n", host.name)
return
}
}
}
func hostSend(clientCh []*Client) {
i := 1
for {
msg := fmt.Sprintf("msg%d", i)
i++
fmt.Println("host发送消息:", msg)
for _, v := range clientCh {
v.source <- msg
}
time.Sleep(time.Second)
}
}
找出这段代码的问题,并改错
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
fmt.Println(i)
wg.Done()
}()
}
wg.Wait()
}
因为i的地址始终不变,所以协程打印出来的始终是10,解决方法:设置一个临时变量
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
tmp := i
go func(i int) {
fmt.Println(i)
wg.Done()
}(tmp)
}
wg.Wait()
}
// isPrime 函数用于判断整数是否为素数
func isPrime(num int) bool {
if num <= 1 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
return false
}
}
return true
}
func main() {
ch := make(chan int, 0)
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < len(numbers); i++ {
go func(i int) {
fmt.Println(numbers[i])
if isPrime(numbers[i]) {
ch <- numbers[i]
}
}(i)
}
firstPrime := <-ch
fmt.Println("The first prime number found is:", firstPrime)
}
错误示例:
package main
import (
"fmt"
"math"
)
// isPrime 函数用于判断整数是否为素数
func isPrime(num int) bool {
if num <= 1 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
return false
}
}
return true
}
func main() {
ch := make(chan int, 0)
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < len(numbers); i++ {
go func() {
if isPrime(numbers[i]) {
ch <- numbers[i]
}
}()
}
firstPrime := <-ch
fmt.Println("The first prime number found is:", firstPrime)
}
找到所有素数
package main
import (
"fmt"
"math"
"sync"
)
// isPrime 函数用于判断整数是否为素数
func isPrime(num int) bool {
if num <= 1 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
return false
}
}
return true
}
func main() {
var wg sync.WaitGroup
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < len(numbers); i++ {
wg.Add(1)
go func(i int) {
if isPrime(numbers[i]) {
fmt.Println(numbers[i])
}
wg.Done()
}(i)
}
wg.Wait()
}
使用管道实现找到所有素数
package main
import (
"fmt"
"math"
"sync"
)
// isPrime 函数用于判断整数是否为素数
func isPrime(num int) bool {
if num <= 1 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
if num%i == 0 {
return false
}
}
return true
}
func main() {
var wg sync.WaitGroup
ch := make(chan int, 0)
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < len(numbers); i++ {
wg.Add(1)
go func(i int) {
if isPrime(numbers[i]) {
ch <- numbers[i]
}
wg.Done()
}(i)
}
go func() {
wg.Wait()
close(ch)
}()
for prime := range ch {
fmt.Println(prime)
}
}