Go 转到对指针方法的并发访问
我试图理解当您并发访问指针方法时会发生什么 我有一个指针地图,并衍生出一些围棋例程。我将映射传递到每个go例程中,每个go例程将使用映射中的一个值。没有任何东西被写入地图,只有从中读取 地图很小,只有4个键,因此可能有多个围棋程序使用地图中的相同值 问题是,当两个go例程调用同一指针的方法时会发生什么?我会得到不可预测的结果吗 编辑 示例:我把地图部分拿出来,因为这不是我要问的问题 我有Go 转到对指针方法的并发访问,go,goroutine,Go,Goroutine,我试图理解当您并发访问指针方法时会发生什么 我有一个指针地图,并衍生出一些围棋例程。我将映射传递到每个go例程中,每个go例程将使用映射中的一个值。没有任何东西被写入地图,只有从中读取 地图很小,只有4个键,因此可能有多个围棋程序使用地图中的相同值 问题是,当两个go例程调用同一指针的方法时会发生什么?我会得到不可预测的结果吗 编辑 示例:我把地图部分拿出来,因为这不是我要问的问题 我有foo这是一个类型为MyStruct的指针,这个结构有一个接受参数的方法DoSomething。在main函数
foo
这是一个类型为MyStruct
的指针,这个结构有一个接受参数的方法DoSomething
。在main
函数中,我创建了两个go例程
,它们都调用foo.DoSomething
传递不同的值。在本例中,第一个go例程的计算量要比第二个例程大得多(这里仅使用睡眠时间来模拟计算)。同样,结构中没有任何变化,我只是调用structures方法。当第一个go例程仍在使用该方法时,我是否需要担心第二个go例程调用foo.DoSomething
package main
import (
"log"
"time"
)
type MyStruct struct {
}
func (self *MyStruct) DoSomething(value int) {
log.Printf("%d Start", value)
calculation_time := time.Duration(value) * time.Second
log.Printf("%d Calculating", value, calculation_time)
time.Sleep(calculation_time)
log.Printf("%d Done", value)
}
func main() {
var foo = new(MyStruct)
go foo.DoSomething(5)
// is this method call a problem when the first one is still working?
go foo.DoSomething(2)
time.Sleep(time.Duration(6 * time.Second))
}
任何指针都被认为不是线程安全的。go例程应该被视为一个单独的线程,即使它可能不是。Go例程通过操作系统线程进行多路复用 如果该值始终为只读(永远不会更改),则可以根据需要读取任意多个go例程。一旦更改该值,就会得到不一致的结果 要同步访问并避免问题(和潜在的恐慌),您必须使用。因此,您可以使用getter和setter函数,而不是直接读/写。getter将使用
m.RLock()
和m.RUnlock()
。setter将使用m.Lock()
和m.Unlock()
使用互斥锁时,请尝试尽快解锁。将代码尽可能短地保持在锁定和解锁之间:
m.Lock()
// Do what you need to do for the lock
mymap[key] = value
m.Unlock()
// Do everything else here
与之不同的是,它允许您同时拥有任意数量的读卡器(RLock代表readlock)。一旦写入程序尝试获取锁,它就会阻止其他读卡器获取锁,并等待退出的读卡器释放其锁
或者,您可以使用通道在go例程之间传递值。渠道适用于许多情况,并受到鼓励。您可以在中阅读有关并发性的更多信息。不过,频道并不总是适合所有情况,因此这取决于具体情况。Go方法有接收器。可以是指针类型。具有签名的方法,例如:
func (r *R) foo(bar baz) // A method
是as吗
换句话说,接收者,不管是否是指针,只是一个参数槽。现在,您的问题归结为:
当两个go例程使用相同的r值调用上述函数时会发生什么情况
A:看情况。问题配置:
不会因为任何原因重新进入foo
变异foo
(指针对象)不进行协调/同步*r
- 最后一点只是一个特例:如果
在没有协调/同步的情况下改变任何共享状态:任何事情都可能发生foo
如果
foo
避免了上述问题,那么即使具有相同的r值,也可以由多个goroutine同时执行。每当有人在其他人读取变量时修改变量时,就会得到一个竞争条件。在您的示例中,变量foo
/self
由许多goroutine同时读取,但由于在并发访问时没有人修改它,所以一切都很好
一个更有趣的例子是带有一些附加属性的structMyStruct
,例如attribute1
。在这种情况下,同样的规则也适用于属性。您可以同时从不同的goroutine读取它-例如,您的DoSomething
方法也可以打印出self.attribute1
的值-但在此期间不允许修改它
如果希望能够在访问变量时对其进行修改,则需要某种类型的同步原语。惯用的Go方法是,只要您需要来自另一个goroutine的数据,就只使用从单个goroutine访问并通过通道进行通信的局部变量,从而避免同时访问同一个变量
Go中也提供的替代方法是来自
sync
包的原语,如sync.Mutex。sync/atomic
软件包还提供了更细粒度的原语,可用于以原子方式加载/存储/修改/比较和交换变量。感谢您花时间帮助我,但这并不是我想要的问题。我添加了一个edit,其中包含一个代码示例,说明了我想要了解的内容。很抱歉给您带来任何困惑。@Jeff,正如我的回答所说,“如果值始终是只读的(永远不会更改),您可以根据需要读取任意多个go例程。”。它不必是特定于地图的-它是一个指针。这同样适用。
func foo(r *R, bar baz) // A plain old function