面试题答案
一键面试1. 函数调用规约相关问题
- 数据竞争:当多个goroutine同时读写共享数据时,可能会导致数据竞争问题。例如一个goroutine在读取数据时,另一个goroutine同时在修改该数据,这会导致读取到的数据不一致或者是无效数据。
- 资源共享:多个goroutine可能会共享一些资源,如文件描述符、数据库连接等。如果没有正确的管理,可能会导致资源的重复使用、泄漏等问题。
2. 设计场景及实现
假设我们有一个银行账户,多个goroutine可能会同时对这个账户进行存款和取款操作。为了避免并发带来的问题,我们可以使用sync.Mutex
来保证同一时间只有一个goroutine能够对账户余额进行操作。
package main
import (
"fmt"
"sync"
)
// BankAccount 定义银行账户结构体
type BankAccount struct {
balance int
mutex sync.Mutex
}
// Deposit 存款操作
func (b *BankAccount) Deposit(amount int) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.balance += amount
}
// Withdraw 取款操作
func (b *BankAccount) Withdraw(amount int) bool {
b.mutex.Lock()
defer b.mutex.Unlock()
if b.balance >= amount {
b.balance -= amount
return true
}
return false
}
// GetBalance 获取账户余额
func (b *BankAccount) GetBalance() int {
b.mutex.Lock()
defer b.mutex.Unlock()
return b.balance
}
func main() {
var wg sync.WaitGroup
account := BankAccount{balance: 100}
// 模拟多个goroutine进行存款和取款操作
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
account.Deposit(10)
}()
}
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
account.Withdraw(20)
}()
}
wg.Wait()
fmt.Println("Final balance:", account.GetBalance())
}
在上述代码中:
BankAccount
结构体包含一个balance
字段表示账户余额,以及一个sync.Mutex
类型的mutex
字段用于同步访问。Deposit
方法在修改balance
之前先锁定mutex
,操作完成后解锁,确保同一时间只有一个goroutine能执行存款操作。Withdraw
方法类似,先锁定mutex
,检查余额是否足够,然后进行取款操作并解锁。GetBalance
方法同样通过锁定和解锁mutex
来安全地获取账户余额。
通过这种方式,使用sync.Mutex
来遵循函数调用规约,有效地避免了并发操作带来的数据竞争和资源共享问题,保证了银行账户操作的正确性。