面试题答案
一键面试-
同步机制:
- 使用
sync.WaitGroup
来等待所有协程完成。WaitGroup
可以让主协程阻塞,直到所有需要等待的协程都调用了Done
方法。 - 使用
sync.Mutex
来保护共享资源,防止资源竞争。不过在Go语言中,优先推荐使用通道(channel)来进行数据传递和同步,减少对锁的依赖。
- 使用
-
数据结构:
- 对于不同类型的结果,可以使用结构体(struct)来封装。例如:
type Result struct { IntResult int StringResult string // 其他类型的结果字段 }
- 使用
map
来存储每个协程的结果,键可以是协程的标识(如ID),值是上述封装结果的结构体。例如:
var results map[int]Result
- 也可以使用通道(channel)来传递结果。创建一个结果通道:
resultCh := make(chan Result)
-
避免资源竞争:
- 使用通道:
- 每个协程将结果发送到通道
resultCh
中。例如:
go func() { var res Result // 计算结果 res.IntResult = 10 res.StringResult = "test" resultCh <- res }()
- 主协程从通道中接收结果,由于通道本身是线程安全的,这样就避免了资源竞争。
var finalResults []Result for i := 0; i < numOfGoroutines; i++ { finalResults = append(finalResults, <-resultCh) } close(resultCh)
- 每个协程将结果发送到通道
- 使用锁(若非要使用共享资源的场景):
- 如果要使用共享的
results map
,则在对results
进行读写操作时,需要加锁。例如:
var mu sync.Mutex go func(id int) { var res Result // 计算结果 res.IntResult = 10 res.StringResult = "test" mu.Lock() results[id] = res mu.Unlock() }(1)
- 如果要使用共享的
- 整体示例代码(使用通道方式):
package main import ( "fmt" ) type Result struct { IntResult int StringResult string } func main() { numOfGoroutines := 3 resultCh := make(chan Result) for i := 0; i < numOfGoroutines; i++ { go func(id int) { var res Result res.IntResult = id * 10 res.StringResult = fmt.Sprintf("result %d", id) resultCh <- res }(i) } var finalResults []Result for i := 0; i < numOfGoroutines; i++ { finalResults = append(finalResults, <-resultCh) } close(resultCh) for _, res := range finalResults { fmt.Printf("Int: %d, String: %s\n", res.IntResult, res.StringResult) } }
- 使用通道:
这样通过合理使用通道和同步机制,能有效地收集和处理多个协程的不同类型结果,并避免资源竞争,提高程序在高并发场景下的性能。