golang-design / go-questions Goto Github PK
View Code? Open in Web Editor NEW📖 Go 程序员面试笔试宝典 | 从问题切入,串连 Go 语言相关的所有知识,融会贯通。 https://golang.design/go-questions
Home Page: https://golang.design/go-questions
License: GNU General Public License v3.0
📖 Go 程序员面试笔试宝典 | 从问题切入,串连 Go 语言相关的所有知识,融会贯通。 https://golang.design/go-questions
Home Page: https://golang.design/go-questions
License: GNU General Public License v3.0
dijkstra style barrier 需要栈重扫,不是因为文中说的原因,而是因为 Go 中出于性能考虑不对栈上保存的指针加 barrier。这一点在 proposal 17503 中讲的很清楚:“However, it also has disadvantages. In particular, it presents a trade-off for pointers on stacks: either writes to pointers on the stack must have write barriers, which is prohibitively expensive, or stacks must be permagrey. Go chooses the later, which means that many stacks must be re-scanned during STW. ”
对于文中的 case,并不影响 GC 的正确性,只是让 GC 更加保守。即使没有栈重扫,那个被错误染黑的 A 在下次 GC 也会被回收掉。
“因此我们所说的 Go 中的写屏障、混合写屏障,其实是指赋值器的写屏障,赋值器的写屏障作为一种同步机制,使赋值器在进行指针写操作时,能够“通知”回收器,进而不会破坏弱三色不变性。”
写屏障这样描述似乎有些容易和 memory barrier 混淆呢,gc barrier 只是插入的一些代码片段,而 memory barrier 则是一种并发同步操作。
尊敬的作者您好, 请问在书中78页提供的“有关优雅关闭channel的样例代码“中,假如sender向中间人(toStop)发起关闭的dataCh的信号时,不会出现dataCh无法被完全消费,从而导致内存泄漏的风险吗?
是否可以新增有關go的錯誤處理機制?
謝謝
作者你好,想请问下,关于书中第 201 页以及其他一些函数中会用到一个 get_tls 方法。我能理解汇编可以通过 fs 段找到 m.tls,但是想问下这里为啥不能直接在 m 这个结构体上获取 g 呀?比如在这个 schedinit 函数中,m0 就是和他同一个包的全局变量,直接从它身上把 m0.tls 捞出来再去拿 g,这样会有什么问题么?
另外还想请问下,所谓的把 m 和主线程绑定,我理解本质上就是通过系统调用把 m.tls[1] 的地址存到 fs 段指向的内存,这个的目的除了是可以直接通过汇编的方式以 fs 寄存器找到当前的 m.tls(比如 get_tls)之外,还有其他的什么作用么?
另外有个 typo,在图片中的 “BX 存器里面现在放的是当前 g 结构体对象的地址”中的 BX 后边少了个寄存器的 “寄”。
A.ref1 = nil:移除灰色对象 A 对白色对象 B 的引用(ref2)
A.ref1 = nil:移除灰色对象 A 对白色对象 B 的引用(ref1)
原文中这段不准确吧:
k1 == k2 时,可认为 k1 和 k2 是同一个 key。如果是结构体,则需要它们的字段值都相等,才被认为是相同的 key。
应该是hash后的值相等和字面值相等才是同一个key,很多字面值相等的,hash出来的值不一定相等,比如引用
G 变成 _Grunnale 状态之后
G 变成 _Grunnable 状态之后
Golang 的内存分配机制有两大策略
顺序分配 (sequential allocation) 和
自由表分配 (free-list allocation)
其中,顺序分配比较迎合 Go Routine 的执行栈,因为一次可以分配整块内存空间
但是问题来了,Go Routine 的执行栈要扩容,如果用 自由表分配 扩容时,就不需要重新复制整个 Go Routine 的执行栈
所以 Golang 应是以 自由表分配 为主比较合理?
我的观点正确吗?谢谢
我在浏览其他博文的时候发现有提到go 1.14及之后的版本解决了这个问题。我在1.14的Release Notes中发现Goroutines 现在是异步可抢占的变为了异步抢占。
A.ref1 = nil: 移除灰色对象 A 对白色对象 B 的引用 (ref2);
根据第389页顶部的图 14-5 来看,A.ref1 = B,所以原句里括号的部分是 ref1 吧
A.ref1 = nil: 移除灰色对象 A 对白色对象 B 的引用 (ref1);
必要时,请附上相关页面的照片或者截图
请在此描述你的问题,提问前请参考提问的智慧
原文是这么说的:
myAppend 函数里,虽然改变了 s,但它只是一个值传递,并不会影响外层的 s,因此第一行打印出来的结果仍然是 [1 1 1]。
这个地方我在第一次看到的时候有点歧义,虽说slice是一个值传递,但是slice中是包含是指向数组的指针的。按理说,值传递的也是数组的指针。
经过验证,不影响的准确原因应该是append触发了slice的扩容,扩容会导致copy,也就是说slice结构体中指向数组的指针发生了变化。因此外层的s不会发生变化。
如果是直接修改slice元素,内外层都会改变
func myAppend(s []int) []int {
//s = append(s, 100)
s[0] = 100
fmt.Printf("s point out func: %p, %p\n", s, &s)
return s
}
我个人的理解,如有不对,欢迎讨论~
缓冲区是否有数据?
- 是 ...
- 否 -> (返回true, true) -> 复制缓冲区元素
缓冲区是否有数据?
- 是 -> (返回true, true) -> 复制缓冲区元素
- 否 ...
所以如果没理解错的话,这好像是个比较大的错误了?
原文:“我们之前讲过的 makeslice
函数返回的是 Slice
结构体”,包括源码函数原型实例。
新版有点变化了。
对 “IsClosed函数返回的结果仅代表那个瞬间” 的解释可能有笔下误。“IsClosed函数返回true,但这时有另一个goroutine关闭了channel” 应改为 “IsClosed函数返回false,但这时有另一个goroutine关闭了channel”
其次,IsClosed 函数返回的结果仅代表调用那个瞬间,并不能保证调用之后会不会有其他 goroutine 对它进行了一些操作,改变了它的这种状态。例如,IsClosed 函数返回 true,但这时有另一个 goroutine 关闭了 channel,而你还拿着这个过时的 “channel 未关闭”的信息,向其发送数据,就会导致 panic 的发生。当然,一个 channel 不会被重复关闭两次,如果 IsClosed 函数返回的结果是 true,说明 channel 是真的关闭了。
其次,IsClosed 函数返回的结果仅代表调用那个瞬间,并不能保证调用之后会不会有其他 goroutine 对它进行了一些操作,改变了它的这种状态。例如,IsClosed 函数返回 false,但这时有另一个 goroutine 关闭了 channel,而你还拿着这个过时的 “channel 未关闭”的信息,向其发送数据,就会导致 panic 的发生。当然,一个 channel 不会被重复关闭两次,如果 IsClosed 函数返回的结果是 true,说明 channel 是真的关闭了。
复制原文段落
代码示例与讲解中图4-14的不符
修改后的段落
必要时,请附上相关页面的照片或者截图
在hugo自动生成页面时,插入更新日期
不再需要手动维护
B=5时 bucket num 由 hash 的低 5 位决定
// 比如 B=5,那 m 就是31,二进制是全 1
// 求 bucket num 时,将 hash 与 m 相与,
// 达到 bucket num 由 hash 的低 8 位决定的效果
m := uintptr(1)<<h.B - 1
B为5时 bucket num 由 hash 的低 5 位决定
// 比如 B=5,那 m 就是31,二进制是全 1
// 求 bucket num 时,将 hash 与 m 相与,
// 达到 bucket num 由 hash 的低 5 位决定的效果
m := uintptr(1)<<h.B - 1
数组和切片有什么异同.md这个里面给s2赋值100后,,打印s1并不会有100,图是不是画错了
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}
return *(*[]byte)(unsafe.Pointer(&bh))
}
1,这里的Data 是一个uintptr整型,把stringHeader.Data作为值拷贝,后面gc不会移动或者回收该uintptr指向的内存吗?
2,在官方文档里面的描述是这样的:
// In general, reflect.SliceHeader and reflect.StringHeader should be used
// only as *reflect.SliceHeader and *reflect.StringHeader pointing at actual
// slices or strings, never as plain structs.
// A program should not declare or allocate variables of these struct types.
// // INVALID: a directly-declared header will not hold Data as a reference.
// var hdr reflect.StringHeader
// hdr.Data = uintptr(unsafe.Pointer(p))
// hdr.Len = n
// s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost
你的转换函数是不是换成下面的更好?
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
var b []byte
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pbytes.Data = stringHeader.Data
pbytes.Len = stringHeader.Len
pbytes.Cap = stringHeader.Cap
return b
}
如题
复制原文段落
这时和P绑定的G正在进行系统调用,无法执行其他的G
应该是P绑定的M正在进行系统调用?
修改后的段落
必要时,请附上相关页面的照片或者截图
”调度器“一章中,“描述scheduler的初始化过程”和“主goroutine如何创建“两节顺序颠倒了
搬迁的目的就是将老的 buckets 搬迁到新的 buckets。而通过前面的说明我们知道,应对条件 1,新的 buckets 数量是之前的一倍,应对条件 2,新的 buckets 数量和之前相等。
对于条件 1,从老的 buckets 搬迁到新的 buckets,由于 bucktes 数量不变,因此可以按序号来搬,比如原来在 0 号 bucktes,到新的地方后,仍然放在 0 号 buckets。
对于条件 2,就没这么简单了。要重新计算 key 的哈希,才能决定它到底落在哪个 bucket。例如,原来 B = 5,计算出 key 的哈希后,只用看它的低 5 位,就能决定它落在哪个 bucket。扩容后,B 变成了 6,因此需要多看一位,它的低 6 位决定 key 落在哪个 bucket。这称为 rehash。
条件1是buckets数量翻倍,条件2是sizeSameGrow,下面描述错误,与上下文不一致。
再次向S2追加元素200:
`s2 = append(s2, 100)`
再次向S2追加元素200:
`s2 = append(s2, 200)`这里应该是200不是100
必要时,请附上相关页面的照片或者截图
原文页码:279页
问题:该页最后一行,关于Go内存问题的Issue是不是贴错了,书中写的是#43430
As 应该是判断是否为同一个类型,Is 是判断是否为同一个值
复制原文段落
修改后的段落
必要时,请附上相关页面的照片或者截图
欧神好, 按照yuasa写屏障的图示, 当C作为黑色对象去引用白色对象B, Yuasa屏障将C变为灰色, B颜色不变. 这不是避免满足了条件1吗. 不允许黑色对象去引用白色对象..
在线文档中看到字符串转切片的代码
//方法一
func string2bytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s))
}
运行后转出来的切片cap字段值是824634806128,并且append操作会报如下错误
unexpected fault address 0x10a4280
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0x10a4280 pc=0x108b0b6]
网上另一种方案,转出来后的切片是可以像正常切片一样append,修改。
//方法二
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}
runtime.KeepAlive(&s)
return *(*[]byte)(unsafe.Pointer(&bh))
}
StringHeader 比 SliceHeader 缺少cap字段的,方法一这样转是不是存在问题?请您解答一下
testSlice := [...]int{1, 2}
newTestSlice := testSlice[2:]
for _, v := range newTestSlice {
log.Print(v)
}
testSlice := [...]int{1, 2}
newTestSlice := testSlice[3:]
for _, v := range newTestSlice {
log.Print(v)
}
output:
invalid slice index 3 (out of bounds for 2-element array)
直接取 testSlice[2]
也会报panic。
以上情况能加到数组和切片中去说明一下吗?
https://golang.design/go-questions/sched/when/
复制原文段落
还包括 “函数调用”的时候,每个函数头都有一行栈检查代码。会有一个背景程序(来达到抢占式调度的目的)定时污染这个栈limit,导致程序进入runtime,
触发调度
参考 https://www.youtube.com/watch?v=-K11rY57K7k
52:24 function prologue
52:41 spoof stack limit
或者也可以参考 https://golangbyexample.com/goroutines-golang/
修改后的段落
必要时,请附上相关页面的照片或者截图
func() {
t = t + 5
}
func() {
t = t + 5
}()
修改后的段落
必要时,请附上相关页面的照片或者截图
有无电子版出售,人在国外。
// 初始化 hamp
// 初始化 hmap
《如何实现字符串和byte切片的零拷贝转换》章节,在1.20版之后有变化了,原方法后面会不适用了。
新的方法:
func StringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func BytesToString(b []byte) string {
return unsafe.String(&b[0], len(b))
}
https://github.com/qcrao/Go-Questions/blob/master/%E6%95%B0%E7%BB%84%E5%92%8C%E5%88%87%E7%89%87/%E5%88%87%E7%89%87%E4%BD%9C%E4%B8%BA%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0.md
这里第一段代码给出的例子里,f
函数内部对元素的+1影响到了外部的s
,这是什么原因?不是很理解
计算 $H_T$ 的最终结论(从 Go 1.10 时开始 $h_t$ 增加了上界 $0.95 \rho$,从 Go 1.14 开始时 $h_t$ 增加了下界 0.6)
计算 $H_T$ 的最终结论(从 Go 1.10 时开始 $h_t$ 增加了上界 $0.95 \rho$,从 Go 1.14 时开始 $h_t$ 增加了下界 $0.6 \rho$)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.