Golang Go语言标准库 log 的一个源码疑问

发布于 1周前 作者 phonegap100 来自 Go语言
func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.out = w
	isDiscard := int32(0)
	if w == io.Discard {
		isDiscard = 1
	}
	atomic.StoreInt32(&l.isDiscard, isDiscard)
}

上面这段代码用了 atomic.StoreInt32 的意义在哪里?

func (l *Logger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.out = w
if w == io.Discard {
	l.isDiscard = 1
}

}

跟这样写有啥区别?


Golang Go语言标准库 log 的一个源码疑问

更多关于Golang Go语言标准库 log 的一个源码疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

16 回复

In the terminology of the Go memory model, if the effect of an atomic operation A is observed by atomic operation B, then A “synchronizes before” B. Additionally, all the atomic operations executed in a program behave as though executed in some sequentially consistent order. This definition provides the same semantics as C++'s sequentially consistent atomics and Java’s volatile variables.

搜一下 Memory Model

更多关于Golang Go语言标准库 log 的一个源码疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


emmm ,我觉得是,想象一个极端场景,16 位机器存储一个 32 位的数字,那么就会需要至少两条 CPU 指令,分别写高位和低位,这样就存在脏读的可能性

所以需要一个原子操作来防止这种情况

因为有好几个地方无锁读取 isDiscard

所以都使用 atomic 来无锁化读写 isDiscard

都是高手啊。

我写过类似的代码,锁内部还是用原子操作。
原因是,其他地方不想加锁,而只是使用原子操作。

按理说所有读取和写入都加锁的话,没必要用 atomic

Java 的 Memory Model 网上资料多一点,原理和要做的事都一样的

除了#2 所说 16 位机器问题,atomic 还确保了 l.isDiscard=0/1 一定在 l.out = w 之后,不会乱序执行,进而确保无锁使用 l.isDiscard 时它的结果一定符合 w == io.Discard ,推荐按#1 所说 Memory Model 完整了解一下

答案应该是 5 楼吧。

无锁读取,有锁修改,比读写锁竞争少

应该在其他地方 l.isDiscard 被并发无锁读写,所以用了原子操作

我问了一下 OpenAI GPT-3 答案差不多

https://jike.info/topic/14265/

我不太懂,加了锁的话不是就保证了内存的顺序,保证 l.isDiscard=0/1 一定在 l.out = w 之后, atomic 应该只是因为其他地方存在无锁读取吧

当然,我很乐意帮你解答关于Go语言标准库log的源码疑问。

Go语言的log包是一个非常基础且常用的日志记录工具。它提供了一组简单的函数,用于输出格式化的日志信息。如果你对log包的源码有疑问,很可能是关于其内部实现机制、线程安全性、日志级别处理或格式化输出等方面。

首先,log包是线程安全的,这意味着你可以在不同的goroutine中安全地使用它。这是通过内部的互斥锁来实现的。

其次,log包并没有提供内置的日志级别支持,如INFO、WARN、ERROR等。这是为了保持其简单性和轻量级。如果需要日志级别支持,你可能需要使用第三方日志库,如logruszap等。

关于格式化输出,log包允许你通过PrintfPrintln等函数自定义日志的格式。这些函数内部使用fmt包来实现格式化功能。

最后,log包的源码实现相对简单,主要涉及到日志输出的配置(如输出目标、前缀、标志等)、日志信息的收集和输出等。你可以通过阅读源码来了解其内部工作原理。

如果你能提供更具体的疑问点或代码示例,我可以给出更精确的回答。希望这些信息对你有所帮助!如果你有其他问题或需要进一步的帮助,请随时告诉我。

回到顶部