在不同的 goroutine 中替换字符串的值时是否需要互斥量?
Do I need a mutex when replacing the value of a string in different goroutines?
在这种情况下我需要互斥量吗?我正在用一个 goroutine 刷新令牌,该令牌在另一个 goroutine 中使用。换句话说,我的令牌是否会在某个时候为空,以便响应将是 401
?
如果是,它是结构 c *threatq
的一部分还是一个简单的变量,我的意思是,我的代码中有一个 "standalone"。
// IndicatorChannelIterator returns indicators from ThreatQ into a channel.
func (c *threatq) IndicatorChannelIterator() (<-chan *models.Indicator, error) {
// Authenticate
token, err := c.authenticate(c.clientID, c.email, c.password)
if err != nil {
return nil, fmt.Errorf("Error while authenticating to TQ : %s", err)
}
// Periodically refresh the token
ticker := time.NewTicker(30 * time.Minute)
go func() {
for range ticker.C {
token, err = c.authenticate(c.clientID, c.email, c.password)
if err != nil {
logrus.Errorf("Error while authenticating to TQ : %s", err)
}
}
}()
// Prepare the query
query := &Query{}
// Get the first page
firstTQResponse, err := c.advancedSearch(query, token, 0)
if err != nil {
return nil, fmt.Errorf("Error while getting the first page from TQ : %s", err)
}
// Create the channel
indicators := make(chan *models.Indicator)
// Request the others
go func() {
req := 1
total := firstTQResponse.Total
for offset := 0; offset < total; offset += c.perPage {
// Search the indicators
tqResponse, err := c.advancedSearch(query, token, offset)
if err != nil {
logrus.Errorf("Error while getting the indicators from TQ : %s", err)
continue
}
...
是的,您也可以在启用 -race
标志的情况下尝试 运行 此测试。 Go 的竞争检测器可能会告诉您令牌是跨多个 goroutine 的共享变量。因此,它必须用 Mutex
或 RWMutex
.
保护
在你的情况下,我认为 RWMutex
更合适,因为有一个 goroutine 每 30 分钟更改(即写入)token
的状态,另一个 goroutine 读取它的值。
如果您不使用锁保护共享变量,第二个 goroutine 可能会读取旧值 token
,该值可能已过期。
规则很简单:如果从多个 goroutine 访问一个变量并且其中至少有一个是写入,则需要显式同步。
你的情况是这样:你的一个 goroutine 写入 token
变量(还有 err
变量!),另一个读取它,所以你必须同步访问。
因为 token
不是 threatq
结构的字段,所以放置保护它的互斥锁是不明智的。始终将互斥体放在它应该保护的数据附近。
一些注意事项:如前所述,您还从多个 goroutine 中写入和读取本地 err
变量。你不应该这样做,而是创建另一个局部变量来保存来自其他 goroutines 的错误(除非你想 "translfer" goroutines 之间的错误,但这里不是这种情况)。
查看相关问题:
Should we synchronize variable assignment in goroutine?
Why does this code cause data race?
在这种情况下我需要互斥量吗?我正在用一个 goroutine 刷新令牌,该令牌在另一个 goroutine 中使用。换句话说,我的令牌是否会在某个时候为空,以便响应将是 401
?
如果是,它是结构 c *threatq
的一部分还是一个简单的变量,我的意思是,我的代码中有一个 "standalone"。
// IndicatorChannelIterator returns indicators from ThreatQ into a channel.
func (c *threatq) IndicatorChannelIterator() (<-chan *models.Indicator, error) {
// Authenticate
token, err := c.authenticate(c.clientID, c.email, c.password)
if err != nil {
return nil, fmt.Errorf("Error while authenticating to TQ : %s", err)
}
// Periodically refresh the token
ticker := time.NewTicker(30 * time.Minute)
go func() {
for range ticker.C {
token, err = c.authenticate(c.clientID, c.email, c.password)
if err != nil {
logrus.Errorf("Error while authenticating to TQ : %s", err)
}
}
}()
// Prepare the query
query := &Query{}
// Get the first page
firstTQResponse, err := c.advancedSearch(query, token, 0)
if err != nil {
return nil, fmt.Errorf("Error while getting the first page from TQ : %s", err)
}
// Create the channel
indicators := make(chan *models.Indicator)
// Request the others
go func() {
req := 1
total := firstTQResponse.Total
for offset := 0; offset < total; offset += c.perPage {
// Search the indicators
tqResponse, err := c.advancedSearch(query, token, offset)
if err != nil {
logrus.Errorf("Error while getting the indicators from TQ : %s", err)
continue
}
...
是的,您也可以在启用 -race
标志的情况下尝试 运行 此测试。 Go 的竞争检测器可能会告诉您令牌是跨多个 goroutine 的共享变量。因此,它必须用 Mutex
或 RWMutex
.
在你的情况下,我认为 RWMutex
更合适,因为有一个 goroutine 每 30 分钟更改(即写入)token
的状态,另一个 goroutine 读取它的值。
如果您不使用锁保护共享变量,第二个 goroutine 可能会读取旧值 token
,该值可能已过期。
规则很简单:如果从多个 goroutine 访问一个变量并且其中至少有一个是写入,则需要显式同步。
你的情况是这样:你的一个 goroutine 写入 token
变量(还有 err
变量!),另一个读取它,所以你必须同步访问。
因为 token
不是 threatq
结构的字段,所以放置保护它的互斥锁是不明智的。始终将互斥体放在它应该保护的数据附近。
一些注意事项:如前所述,您还从多个 goroutine 中写入和读取本地 err
变量。你不应该这样做,而是创建另一个局部变量来保存来自其他 goroutines 的错误(除非你想 "translfer" goroutines 之间的错误,但这里不是这种情况)。
查看相关问题:
Should we synchronize variable assignment in goroutine?
Why does this code cause data race?