面试题答案
一键面试通道创建与销毁时机优化
- 提前创建:在系统初始化阶段创建通道,避免在高并发场景下频繁创建和销毁通道带来的开销。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func producer(ch chan int) {
defer wg.Done()
for i := 0; i < 1000; i++ {
ch <- i
}
close(ch)
}
func consumer(ch chan int) {
defer wg.Done()
for val := range ch {
fmt.Println("Consumed:", val)
}
}
func main() {
ch := make(chan int, 100)
wg.Add(2)
go producer(ch)
go consumer(ch)
wg.Wait()
}
- 避免不必要销毁:仅在确实不再需要通道时关闭它,防止提前关闭导致数据丢失或消费者异常。
数据序列化方式优化
- 使用高效序列化库:例如
encoding/gob
在Go中性能较好且简单易用。如果数据结构简单,也可以考虑手动打包数据以减少序列化开销。
package main
import (
"bytes"
"encoding/gob"
"fmt"
"sync"
)
type Data struct {
ID int
Name string
}
var wg sync.WaitGroup
func producer(ch chan []byte) {
defer wg.Done()
data := Data{ID: 1, Name: "example"}
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(data)
if err != nil {
fmt.Println("Encoding error:", err)
return
}
ch <- buf.Bytes()
close(ch)
}
func consumer(ch chan []byte) {
defer wg.Done()
for data := range ch {
var decoded Data
dec := gob.NewDecoder(bytes.NewBuffer(data))
err := dec.Decode(&decoded)
if err != nil {
fmt.Println("Decoding error:", err)
continue
}
fmt.Println("Consumed:", decoded)
}
}
func main() {
ch := make(chan []byte, 10)
wg.Add(2)
go producer(ch)
go consumer(ch)
wg.Wait()
}
结合sync包工具优化
- 使用
sync.WaitGroup
:用于同步协程,确保所有协程完成任务后再退出程序,避免通道未处理完数据就关闭。如上述示例代码。 - 使用
sync.Mutex
:当多个协程需要访问共享资源时,加锁防止数据竞争。例如多个协程可能同时向一个通道发送数据,可使用锁保护。
package main
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
count int
ch chan int
)
func increment() {
mu.Lock()
count++
ch <- count
mu.Unlock()
}
func main() {
ch = make(chan int, 10)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
increment()
}()
}
go func() {
wg.Wait()
close(ch)
}()
for val := range ch {
fmt.Println("Received:", val)
}
}
性能对比分析思路
- 使用
time
包:在优化前和优化后的关键代码段前后记录时间。例如在数据发送和接收前后记录时间,计算总耗时。
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan int, 100)
var wg sync.WaitGroup
wg.Add(2)
start := time.Now()
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
ch <- i
}
close(ch)
}()
go func() {
defer wg.Done()
for range ch {
}
}()
wg.Wait()
elapsed := time.Since(start)
fmt.Println("Total time:", elapsed)
}
- 使用
benchmark
:编写Go基准测试函数,对优化前后的功能进行性能测试。例如:
package main
import (
"testing"
)
func BenchmarkOriginal(b *testing.B) {
for n := 0; n < b.N; n++ {
ch := make(chan int, 100)
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
ch <- i
}
close(ch)
}()
go func() {
defer wg.Done()
for range ch {
}
}()
wg.Wait()
}
}
func BenchmarkOptimized(b *testing.B) {
ch := make(chan int, 100)
var wg sync.WaitGroup
wg.Add(2)
for n := 0; n < b.N; n++ {
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
ch <- i
}
close(ch)
}()
go func() {
defer wg.Done()
for range ch {
}
}()
wg.Wait()
}
}
通过go test -bench=.
命令运行基准测试,对比优化前后的平均执行时间、内存使用等指标。