golang并发编程面试题

1、用两个协程打印交替打印字母和数字,例如A1B2C3D4E5…

注意: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()
}

2、多个协程交替打印数字

参考: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
	}
}

3、使用channel实现广播通知(一对多)

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)
	}
}

4、for循环遍历地址不变

找出这段代码的问题,并改错

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()
}

5、使用并发编程找到第一个为素数的的数,并返回

// 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)
	}
}

你可能感兴趣的:(golang,开发语言)