go标准库container支持multi goroutine吗?

214 views
Skip to first unread message

guagua

unread,
Nov 21, 2014, 12:48:45 AM11/21/14
to golang...@googlegroups.com
rt

hyper-carrot

unread,
Nov 21, 2014, 1:28:59 AM11/21/14
to golang...@googlegroups.com

闪看下源码(List),不是并发安全的。这也符合Go语言目前的倾向。

在 2014年11月21日星期五UTC+8下午1时48分45秒,guagua写道:
rt

guagua

unread,
Nov 21, 2014, 1:40:07 AM11/21/14
to golang...@googlegroups.com
我看了也没有任何sync包或atomic包,符合Go语言目前的倾向如何解释?

在 2014年11月21日星期五UTC+8下午2时28分59秒,hyper-carrot写道:

hyper-carrot

unread,
Nov 21, 2014, 1:58:24 AM11/21/14
to golang...@googlegroups.com

类比Go语言现在slice、map等实现。Go语言目前只提供基本的数据结构,而并不在其上附加并发安全的特性。按他们的话来讲就是:提供附加这一特性的数据结构并不困难,但是目前并不是重点。

在 2014年11月21日星期五UTC+8下午2时40分07秒,guagua写道:

hyper-carrot

unread,
Nov 21, 2014, 2:04:32 AM11/21/14
to golang...@googlegroups.com
实际上,使用锁来保障并发安全性在Go语言这里并不受推崇。

相关的讨论可以看这里:http://golanghome.com/post/490 (可以忽略题目只看最后几条评论)

另外,一个参照Java的ConcurrentHashMap搞的并发安全的Map这里:http://golanghome.com/post/517

在 2014年11月21日星期五UTC+8下午2时58分24秒,hyper-carrot写道:

minux

unread,
Nov 21, 2014, 3:28:59 AM11/21/14
to golang...@googlegroups.com
2014-11-21 1:58 GMT-05:00 hyper-carrot <free...@gmail.com>:
> 类比Go语言现在slice、map等实现。Go语言目前只提供基本的数据结构,而并不在其上附加并发安全的特性。按他们的话来讲就是:提供附加这一特性的数据结构并不困难,但是目前并不是重点。
这么说不对。官方的解释参考 http://golang.org/doc/faq#atomic_maps
不是什么不是重点的问题,是因为:
1. 如果需要控制并发访问,一般map/slice等会在一个结构体里,而需要控制并发访问的并不是
这一个map或者slice,而是相关的几个数据结构,这样在语言层面实现这些单独的数据类型的
并发控制意义不大,反而影响了效率。
2. 绝大多数情况这些数据结构是不会被并发访问的,如果强制实现加锁或者采用lock-free 算法,
可能导致绝大多数程序性能下降,但是鉴于上面第一点,只有少数程序受益。

当然语言层面没限制实现必须保证并发访问正确,并不意味着某个实现不能提供这样的保证。

> 在 2014年11月21日星期五UTC+8下午2时40分07秒,guagua写道:
>> 我看了也没有任何sync包或atomic包,符合Go语言目前的倾向如何解释?
准确地说,应该是任何接口,如果没有明确地列出支持并发访问的,一概是不支持并发访问。

guagua

unread,
Nov 21, 2014, 3:37:31 AM11/21/14
to golang...@googlegroups.com
我觉得golang中的基本类型不附加并发安全性完全可以理解,但pkg中的高层API是否可以尝试提供这样的保障。
比如,我现在不能使用container包,就有点遗憾了

minux

unread,
Nov 21, 2014, 3:51:44 AM11/21/14
to golang...@googlegroups.com

2014-11-21 2:04 GMT-05:00 hyper-carrot <free...@gmail.com>:
> 实际上,使用锁来保障并发安全性在Go语言这里并不受推崇。
>
> 相关的讨论可以看这里:http://golanghome.com/post/490 (可以忽略题目只看最后几条评论)
有意思,里面问的好几个问题,我说说我的看法(看来国内的 Go 用户都不喜欢在本邮件列表里
讨论啊。。。)。

atomic/sync.Load* 不用 LOCK 前缀是因为在 x86 和 amd64 上,对齐的读总是原子操作。

关于 release/acquire 语义的问题,有人也对这个提出过质疑,他认为 Go 的 sync/atomic 包没有
用任何 memory barrier 指令(这个主要是说 ARM,x86 的 consistency 保证很强,没这个问题),
我也做了做了若干实验,但是即使在 SMP 环境下,我依然没观察到任何测试失败。但是根据 Go
的 sync/atomic 包的用法来说,所有原子操作基本上都隐含了双向 barrier 的。

> 另外,一个参照Java的ConcurrentHashMap搞的并发安全的Map这里:http://golanghome.com/post/517
细节没看,但是有一句话我得澄清下:“Golang1.4 beta1宣布不再保证unsafe包的兼容性(Go的
设计者对程序员利用unsafe包绕过Go类型系统不满)”

Go 的设计者做出这个改变并不因为程序员利用 unsafe 包绕过类型系统不满,而是从长远考虑,
根本不可能支持任意的使用 unsafe 包的程序。

不再保证使用 unsafe 包的兼容性是 CL 162060043 引入的,根据那个 CL 的说法,事实上 unsafe
的程序不保证兼容一直是默认的:unsafe 操作依赖于 Go 的 runtime 实现;这次只不过是澄清了
这个而已。

实际上,如果想要发展新的更准确、更高性能的 GC,是不可能不对使用 unsafe 的程序做出限制的。
比如,如果一个程序使用 uintptr 来存储一个指向 Go heap 的指针,那么如果要保证这个程序正确,
Go 的 GC 必须是保守 GC(所有 uintptr 都得认为可能是指针)。而大家也知道非保守 GC 的问题,
Go 1.1 开始到 1.4,一直是在试图将 GC 精确化。现在 1.4 终于做到了完美的精确 GC。这时候
别说用 uintptr 保存 Go heap 指针了,如果一个指针在任何时候脱离了 GC 的视线,那么都可能导
致 GC 错误地将对应的内存释放。所以 1.4 在文档里也规定了几种会一定会支持的 uintptr/unsafe.Pointer
用法,同时建议任何使用了 unsafe.Pointer 在升级到 1.4 一定要用 go vet 检查。

minux

unread,
Nov 21, 2014, 3:58:49 AM11/21/14
to golang...@googlegroups.com

2014-11-21 3:37 GMT-05:00 guagua <bette...@gmail.com>:
我觉得golang中的基本类型不附加并发安全性完全可以理解,但pkg中的高层API是否可以尝试提供这样的保障。
比如,我现在不能使用container包,就有点遗憾了
你应该重新读哦的回复。高层和底层数据结构不提供并发访问的支持都是为了给用户最大的选择。
如果你想使用lock-free甚至wait-free的数据结构,godoc.org 上有很多。(实现 lock-free/wait-free
数据结构用 Go 是很合适的,类似,它有 GC,对于绝大多数 lock-free/wait-free 算法,GC都是必
须的,否则很难保证内存不泄露;其次,它又能让用户精确地控制内存布局,类似C/C++,这对于
实现 lock-free 和 wait-free 算法也是很重要的(举个例子:绝大多数情况下,为了避免 false sharing,
结构体需要对 cache line 对齐,在 Java 里这是不可能的,总得借助别的机制),Go 的 sync/atomic
提供了足够多通用的原语,也可以满足需要,不像C/C++,如果不用最新的标准,那就得用不可移
植的编译器扩展或者内嵌汇编)

hyper-carrot

unread,
Dec 4, 2014, 2:59:00 AM12/4/14
to golang...@googlegroups.com
好吧,我就是这个意思,措辞有误。

在 2014年11月21日星期五UTC+8下午4时28分59秒,minux写道:

hyper-carrot

unread,
Dec 4, 2014, 3:14:26 AM12/4/14
to golang...@googlegroups.com
其实,之所以Java如此流行且学习门槛很低,就是因为它的标准库中提供了大量的便捷工具,这可以大大降低应用开发者的成本从而在侧面提高开发效率。我觉得这是极好的。我之所以说不是***不是重点,是因为Go语言设计者还没有精力或不屑于做出这些并发安全的数据结构。你回复的那些内容我只在心里默念了没写出来,对不起楼主。总之,我觉得Go的这种策略无可厚非,但是对于面向用惯了锁的开发者们的语言推广工作没什么好处。

在 2014年11月21日星期五UTC+8下午4时58分49秒,minux写道:

Monnand

unread,
Dec 4, 2014, 1:48:11 PM12/4/14
to golang中文组
2014-12-04 3:14 GMT-05:00 hyper-carrot <free...@gmail.com>:
> 其实,之所以Java如此流行且学习门槛很低,就是因为它的标准库中提供了大量的便捷工具,这可以大大降低应用开发者的成本从而在侧面提高开发效率。我觉得这是极好的。我之所以说不是***不是重点,是因为Go语言设计者还没有精力或不屑于做出这些并发安全的数据结构。你回复的那些内容我只在心里默念了没写出来,对不起楼主。总之,我觉得Go的这种策略无可厚非,但是对于面向用惯了锁的开发者们的语言推广工作没什么好处。

并没有说不用锁啊。只不过Go建议用户自己在结构体里加锁,而不是在基本容器里加锁。事实上,对所有容器加锁这个做法已经是公认的一个java标准库里的问题了。

>
> 在 2014年11月21日星期五UTC+8下午4时58分49秒,minux写道:
>>
>>
>> 2014-11-21 3:37 GMT-05:00 guagua <bette...@gmail.com>:
>>>
>>> 我觉得golang中的基本类型不附加并发安全性完全可以理解,但pkg中的高层API是否可以尝试提供这样的保障。
>>> 比如,我现在不能使用container包,就有点遗憾了
>>
>> 你应该重新读哦的回复。高层和底层数据结构不提供并发访问的支持都是为了给用户最大的选择。
>> 如果你想使用lock-free甚至wait-free的数据结构,godoc.org 上有很多。(实现 lock-free/wait-free
>> 数据结构用 Go 是很合适的,类似,它有 GC,对于绝大多数 lock-free/wait-free 算法,GC都是必
>> 须的,否则很难保证内存不泄露;其次,它又能让用户精确地控制内存布局,类似C/C++,这对于
>> 实现 lock-free 和 wait-free 算法也是很重要的(举个例子:绝大多数情况下,为了避免 false sharing,
>> 结构体需要对 cache line 对齐,在 Java 里这是不可能的,总得借助别的机制),Go 的 sync/atomic
>> 提供了足够多通用的原语,也可以满足需要,不像C/C++,如果不用最新的标准,那就得用不可移
>> 植的编译器扩展或者内嵌汇编)
>>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
> 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

hyper-carrot

unread,
Dec 4, 2014, 7:24:43 PM12/4/14
to golang...@googlegroups.com
Java里又不加锁的,也有加锁的。开发者也可以随意选择,这种便利性不言而喻。Go语言的标准库也很丰富,但是在这方面还有所欠缺。当然了,现在有比这更重要的事要做,而且Go语言还很年轻,不急于这一时,让开发者自己去创造也OK。想当年Java也是在诞生N年后才开始丰富这方面的类库。

在 2014年12月5日星期五UTC+8上午2时48分11秒,Monnand写道:
2014-12-04 3:14 GMT-05:00 hyper-carrot <free...@gmail.com>:
> 其实,之所以Java如此流行且学习门槛很低,就是因为它的标准库中提供了大量的便捷工具,这可以大大降低应用开发者的成本从而在侧面提高开发效率。我觉得这是极好的。我之所以说不是***不是重点,是因为Go语言设计者还没有精力或不屑于做出这些并发安全的数据结构。你回复的那些内容我只在心里默念了没写出来,对不起楼主。总之,我觉得Go的这种策略无可厚非,但是对于面向用惯了锁的开发者们的语言推广工作没什么好处。

并没有说不用锁啊。只不过Go建议用户自己在结构体里加锁,而不是在基本容器里加锁。事实上,对所有容器加锁这个做法已经是公认的一个java标准库里的问题了。

>
> 在 2014年11月21日星期五UTC+8下午4时58分49秒,minux写道:
>>
>>
>> 2014-11-21 3:37 GMT-05:00 guagua <bette...@gmail.com>:
>>>
>>> 我觉得golang中的基本类型不附加并发安全性完全可以理解,但pkg中的高层API是否可以尝试提供这样的保障。
>>> 比如,我现在不能使用container包,就有点遗憾了
>>
>> 你应该重新读哦的回复。高层和底层数据结构不提供并发访问的支持都是为了给用户最大的选择。
>> 如果你想使用lock-free甚至wait-free的数据结构,godoc.org 上有很多。(实现 lock-free/wait-free
>> 数据结构用 Go 是很合适的,类似,它有 GC,对于绝大多数 lock-free/wait-free 算法,GC都是必
>> 须的,否则很难保证内存不泄露;其次,它又能让用户精确地控制内存布局,类似C/C++,这对于
>> 实现 lock-free 和 wait-free 算法也是很重要的(举个例子:绝大多数情况下,为了避免 false sharing,
>> 结构体需要对 cache line 对齐,在 Java 里这是不可能的,总得借助别的机制),Go 的 sync/atomic
>> 提供了足够多通用的原语,也可以满足需要,不像C/C++,如果不用最新的标准,那就得用不可移
>> 植的编译器扩展或者内嵌汇编)
>>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

minux

unread,
Dec 4, 2014, 7:49:53 PM12/4/14
to golang...@googlegroups.com
2014-12-04 19:24 GMT-05:00 hyper-carrot <free...@gmail.com>:
Java里又不加锁的,也有加锁的。开发者也可以随意选择,这种便利性不言而喻。Go语言的标准库也很丰富,但是在这方面还有所欠缺。当然了,现在有比这更重要的事要做,而且Go语言还很年轻,不急于这一时,让开发者自己去创造也OK。想当年Java也是在诞生N年后才开始丰富这方面的类库。
你一直强调 Go 年轻的因素,但是我可以很确定的说,默认数据结构不做并发安全是基本设计理念,
是不会随着时间而改变的。

我前面也解释了多遍了。在构造数据结构的时候,每个子成员都并发安全并不是最优的选择。而且
有些数据结构也很难做语言层面的并发安全,因为可能情况太多了。比如 slice,copy要不要加锁?
append呢(append 还有两种情况)?reslice呢?

越是为并发设计的语言,就越注重在并发处理上的灵活性。不存在 one size fits all 的并发安全方案。
(不然也不需要 Go 了,早就有一个语言一统天下了。)

再说了,就算是每个基础数据结构都是自动加锁的,难道写并发的程序就很简单了么?不一定。加
锁还有顺序的问题,不然很容易死锁。这些都是程序员需要考虑的,语言和环境没办法也不应该替
程序员做决定。

好,你可以说我们要求所有基础数据结构都是 lock-free,但是这并不是很容易做的。map 可以做到,
container/list, container/ring 都可以做到,channel 的 fast-path 可以 lock free(顺便说一句:支持
select 的完全 lock-free channel 实现是非常困难的,你要是做出来了,先去发表论文)。先不考虑
诸如 slice/array/interface 这样的数据类型的并发安全的定义的问题,lock-free 的算法在单核的时
候性能都是(远)低于传统算法的,这样不写并发算法的程序员又不愿意了。

Monnand

unread,
Dec 4, 2014, 8:05:37 PM12/4/14
to golang中文组
我没记错的话,JDK的历史是这样的:

早年间,容器的操作都是加锁的 [0]. 之后遇到了minux前面说的问题,于是意识到给基本容器加锁是一个问题很大的设计,这才引入了没加锁的容器。

基本容器不需要并发安全。因为并发安全的语义是在应用层加入的。更准确说,什么是一个“原子操作”只有在应用层才能知道,在标准库层面,需要什么样的“原子操作”是不清楚的。

我举个例子,如果你要实现一个使用LRU替换算法的key-value缓存。最简单的数据结构可以是:

type LRUCache struct {
lastAccess map[string]time.Time
data map[string]string
maxNrObjects int
}

lastAccess里存储了每个Key的最近一次访问时间;data则存储了每个key对应的value。maxNrObjects表示最多可以存储多少个key-value对。当添加一个新元素的时候,如果当前缓存里存了多于maxNrObjects个数据的话,就找出最后一次访问最早的那个Key(扫描整个lastAccess),然后把这个key从data里面删除,接着再把新元素加入到data中,把这个新元素的访问时间也加入到lastAccess中。

注意:我这个LRU的实现只是处于讲解的目的,实际LRU肯定不会这么实现,因为效率太低。

你可以看到,“添加元素”这个操作本事是一个“原子操作”。它包含了四个对容器的操作:检查data,修改lastAccess,修改data,再修改lastAccess。这四个操作必须逻辑上连续,中间不能打断。这样,结构体就需要重新定义成:

type LRUCache struct {
lastAccess map[string]time.Time
data map[string]string
maxNrObjects int
lock sync.Mutex
}

这里新加入的lock成员,用来控制访问。试想,如果每个基本容器/map都是并发安全,都有锁的话,那么以上的“添加元素”操作,就需要10次锁操作:5次加锁,5次解锁——每个数据结构加/解锁各一次,lock加/解锁一次。而现在Go的设计,则只需要对lock做加锁解锁。

还是我之前说的:标准库不可能知道应用层定义的“原子操作”意味着什么——是两次链表操作+一次哈希表操作?还是仅仅是一次哈希表操作?而这就意味着在标准库提供的数据结构中加上锁是不可能满足用户需求的。为了满足用户需求,用户还需要自己在外面再加一层锁。而这就导致了*不必要*的额外开销。

不知道这么解释你明白了没。

0. http://web.mit.edu/java_v1.0.2/www/apibook/javae.htm

2014-12-04 19:24 GMT-05:00 hyper-carrot <free...@gmail.com>:
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
> 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/7fbf4eaf-b2cd-4ac8-b03c-fb9323b1032e%40googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

hyper-carrot

unread,
Dec 5, 2014, 5:06:22 AM12/5/14
to golang...@googlegroups.com
争这个没用啊,我没说基本数据结构上要加锁,我还没见过哪个语言在基本数据结构上搞并发安全的,我说的是标准库或者扩展库,像container这类的包,麻烦您仔细看看我上面所说的。

在 2014年12月5日星期五UTC+8上午8时49分53秒,minux写道:

hyper-carrot

unread,
Dec 5, 2014, 5:12:04 AM12/5/14
to golang...@googlegroups.com

我说的是标准库,兄弟们!不是基本数据结果,也不是核心的什么数据结构...玩儿转英文的同时千万不要放弃母语啊,谢谢啊!

另外,Monnand同学,我不觉得基本的容器加锁有什么好处,也不想看到这种情况的发生,哪个语言设计者也不会脑残到这么做。我一直在谈论container这里的附加库。我同时也没说在container中都必须的是并发安全的容器,我说的是应该包含这种并发安全的数据结果作为有力的补充。当然,Go语言设计者可能不屑这样做,不管是不是原则性的观点。

在 2014年12月5日星期五UTC+8上午9时05分37秒,Monnand写道:
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

hyper-carrot

unread,
Dec 5, 2014, 5:15:36 AM12/5/14
to golang...@googlegroups.com
就这样吧,不知道争论这个有啥用。丰富函数库肯定是必经之路,这是扩充而不覆盖本应有的基础。我只是表达我希望有这样的扩充的观点,别无其他。

在 2014年11月21日星期五UTC+8下午1时48分45秒,guagua写道:
rt

Monnand

unread,
Dec 5, 2014, 5:45:24 AM12/5/14
to golang中文组
2014-12-05 5:12 GMT-05:00 hyper-carrot <free...@gmail.com>:
>
> 我说的是标准库,兄弟们!不是基本数据结果,也不是核心的什么数据结构...玩儿转英文的同时千万不要放弃母语啊,谢谢啊!

我说的也是标准库。我的天哪,都把java那个链接给你发了。当年java犯过这个错误。你把我之前的例子里的map换成java的HashMap不是一样?utils.HashMap不是java标准库里的?

>
> 另外,Monnand同学,我不觉得基本的容器加锁有什么好处,也不想看到这种情况的发生,哪个语言设计者也不会脑残到这么做。我一直在谈论container这里的附加库。我同时也没说在container中都必须的是并发安全的容器,我说的是应该包含这种并发安全的数据结果作为有力的补充。当然,Go语言设计者可能不屑这样做,不管是不是原则性的观点。

container不就是容器么?没明白你什么意思。
>> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >> >
>> >> >
>> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >
>> > --
>> > --
>> > 官网: http://golang-china.org/
>> > IRC: irc.freenode.net #golang-china
>> > @golangchina
>> > ---
>> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/7fbf4eaf-b2cd-4ac8-b03c-fb9323b1032e%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
> 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/34e80370-e871-4d55-b16e-e48defd137c8%40googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

Kun Li

unread,
Dec 5, 2014, 11:59:46 AM12/5/14
to golang...@googlegroups.com
你的意思是不是说希望在标准库的基础上提供一些像concurrentmap这样的库?

hyper-carrot

unread,
Dec 5, 2014, 8:04:52 PM12/5/14
to golang...@googlegroups.com
我是说扩充和丰富,没说把map或container包里的list变成并发安全的。over。

在 2014年12月5日星期五UTC+8下午6时45分24秒,Monnand写道:
>> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >> >
>> >> >
>> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >
>> > --
>> > --
>> > 官网: http://golang-china.org/
>> > IRC: irc.freenode.net #golang-china
>> > @golangchina
>> > ---
>> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/7fbf4eaf-b2cd-4ac8-b03c-fb9323b1032e%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
> 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

hyper-carrot

unread,
Dec 5, 2014, 8:05:32 PM12/5/14
to golang...@googlegroups.com
对,是这意思。

在 2014年12月6日星期六UTC+8上午12时59分46秒,Kun Li写道:
你的意思是不是说希望在标准库的基础上提供一些像concurrentmap这样的库?

要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

Monnand

unread,
Dec 5, 2014, 10:04:34 PM12/5/14
to golang中文组
你先调整好语气和用词,没人欠你什么也没人打算在邮件列表里跟你吵架。
>> >> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> >> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >> >
>> >> > --
>> >> > --
>> >> > 官网: http://golang-china.org/
>> >> > IRC: irc.freenode.net #golang-china
>> >> > @golangchina
>> >> > ---
>> >> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> >> >
>> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >> >
>> >> >
>> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/7fbf4eaf-b2cd-4ac8-b03c-fb9323b1032e%40googlegroups.com
>> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >
>> > --
>> > --
>> > 官网: http://golang-china.org/
>> > IRC: irc.freenode.net #golang-china
>> > @golangchina
>> > ---
>> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/34e80370-e871-4d55-b16e-e48defd137c8%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛上的“Golang-China”群组。
> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
> 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/399f65f7-d340-4ab8-8893-746d30e7f05a%40googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

minux

unread,
Dec 5, 2014, 11:16:10 PM12/5/14
to golang...@googlegroups.com
2014-12-05 5:06 GMT-05:00 hyper-carrot <free...@gmail.com>:
争这个没用啊,我没说基本数据结构上要加锁,我还没见过哪个语言在基本数据结构上搞并发安全的,我说的是标准库或者扩展库,像container这类的包,麻烦您仔细看看我上面所说的。
我说的基本数据结构包括 container/{list,ring,heap} 这些。而且所有理由对于他们依然成立。
Monnand 也举了非常实际例子了。(你把他举的例子里的 map 换成 container/list,道理
是一样的)

我觉得你在玩文字游戏。非要分开说什么基本数据结构,标准库数据结构/扩展库数据结构,
要那个必要么?我们说的理由,对于所有数据结构都是成立的。不论是什么数据结构,真
正使用的时候往往是组合在一起用的,这时候每个都并发安全不但影响性能,还可能有给
程序员错误的安全感(“我这个结构体中每个成员都是并发安全的,那么我对于这个结构体
的任何操作都是并发安全的”)。

如果你赞成前面引号里的结论是错的,那么如何解决,是不是应该在更高层面确保并发安全
呢?比如说用 channel,比如说整个结构体加一个 sync.Mutex。但是这样一来,每个成员
的并发安全还有必要么?

Go 的设计理念非常明确:
1. 建议使用 channel
2. 不建议轻易使用 sync/atomic
3. 数据结构的并发安全是高层次考虑的东西,每个应用场景的需求都不同,这点应该由程序
员自己把握。

我觉得从这几点中分析出来 Go 不建议自带锁的数据结构(lock-free 的另说)是非常明显的。

关于你说的 Java 比 Go 用户多,这个肯定,但是入门门槛低,这个不一定。或者说,入门,
可能 Java 简单。但是要说掌握,比 Go 难得多。

minux

unread,
Dec 6, 2014, 12:01:55 AM12/6/14
to golang...@googlegroups.com
必须要补充的一点是:目前数据结构(包括语言提供的和标准库提供的)都不是并发安全的,
不是设计者短视,也不是语言年轻或没时间,更不是作者们不屑于写;这是明确的设计决定。

当然反过来,需要提供并发安全的结构,比如 sync.Pool,有比如 net.Conn,则是一定会做
并发安全的。

hyper-carrot

unread,
Dec 6, 2014, 2:53:46 AM12/6/14
to golang...@googlegroups.com
我是很心平气和的,兄弟,咱们只是讨论问题。我只是努力在表达清楚我的观点。至于你理解成什么样子了,可能有我的原因,我表达的不够清楚,但也可能有你的。是吧?咱们客观一点。

在 2014年12月6日星期六UTC+8上午11时04分34秒,Monnand写道:
>> >> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/d47047d9-4ae9-4bc9-8c61-60a6cbc3c35d%40googlegroups.com
>> >> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >> >
>> >> > --
>> >> > --
>> >> > 官网: http://golang-china.org/
>> >> > IRC: irc.freenode.net #golang-china
>> >> > @golangchina
>> >> > ---
>> >> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> >> >
>> >> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >> >
>> >> >
>> >> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/7fbf4eaf-b2cd-4ac8-b03c-fb9323b1032e%40googlegroups.com
>> >> > 要查看更多选项,请访问https://groups.google.com/d/optout
>> >
>> > --
>> > --
>> > 官网: http://golang-china.org/
>> > IRC: irc.freenode.net #golang-china
>> > @golangchina
>> > ---
>> > 您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
>> > 要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com
>> >
>> > 要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/34e80370-e871-4d55-b16e-e48defd137c8%40googlegroups.com
>> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> --
> 官网: http://golang-china.org/
> IRC: irc.freenode.net #golang-china
> @golangchina
> ---
> 您收到此邮件是因为您订阅了Google网上论坛上的“Golang-China”群组。
> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

hyper-carrot

unread,
Dec 6, 2014, 3:05:23 AM12/6/14
to golang...@googlegroups.com
你说的没错,Go语言有自己的理念,我也认同Go语言的这个理念。如果你真的看过Java 7及之后版本的并发库的话,(好吧,我调整措辞,我用第一人称“我”),我看过Java 7的并发包里一些类,真的觉得一些更高层的、并发安全的数据结构会大大降低开发人员的开发成本和门槛。并发安全的程序并不是锁或无锁这么简单,它可能包含了更多意味深长的设计。而不是所有开发人员都想重新实现自己的并发安全实现。这个你不能否认,对吧?不是所有的人都是编程高手。我认为让Go语言真正普惠大众的关键就是提供更多便捷的东西(注意,我没说现在开发Go程序不便捷、也没说Go语言现在不够流行)

另外,Channel并不适合任何场景,锁这种工具还是有必要的,这个工具出现在Go语言的标准库中也充分说明了这一点。

我的观点又一次表达了,你们继续,咱们可以讨论。无论谁对谁错。当然,不一定非对即错。

在 2014年12月6日星期六UTC+8下午12时16分10秒,minux写道:

Jay True

unread,
Dec 6, 2014, 7:10:22 AM12/6/14
to golang...@googlegroups.com
@hyper-carrot

我觉得你也可以举个例子来说明一下吧,只用 Go 现有的东西需要怎样,如果有了你希望的扩展又会如何方便,这样那样的。这样讨论起来也更具体一点儿。

minux

unread,
Dec 6, 2014, 3:41:22 PM12/6/14
to golang...@googlegroups.com
2014-12-06 7:10 GMT-05:00 Jay True <gla...@gmail.com>:
@hyper-carrot

我觉得你也可以举个例子来说明一下吧,只用 Go 现有的东西需要怎样,如果有了你希望的扩展又会如何方便,这样那样的。这样讨论起来也更具体一点儿。
需要注意的一点,提出 Go 增加新特性(不一定是语言特性,可能是标准库加个接口,增加一个包)的请求的,
肯定每个请求都是让某些情况甚至是所有情况更方便的,但是方便性并不是决定一个特性是否值得添加的唯一
因素(甚至不是最重要的因素)。

看 golang-nuts 就能看得出来,有一个几乎模板式的很委婉的回复:我不否认你的提议会使处理XX的时候会更
方便,但是增加每个特性都有它的代价,必须综合地考虑才行……

很多特性都是方便做一个人做小项目的,但是 Go 的目标是数千人合作的数千万行代码的大项目。对每个人方
便和对整个项目有利往往是矛盾的。这也是 Go 对于某些很郁闷人的特性如此坚持的原因(比如 unused import)。

我不否认如果 Go 加入并发安全的数据结构会让某些工作更简单,但是在大项目里,数据结构很少单独使用,
大的数据结构里即使每个小的结构都并发安全,并不意味着整个结构安全(这是我一直说的问题),所以要用
锁的地方,一定要显式地使用,并且一般在定义结构体的时候,锁的位置也是有要求的,锁保护的几个对象
应该和锁在一起,和其他对象用空行分开,且锁排在第一个。(想知道 Google 里面对 Go 代码风格的要求的,
两者有交集,但是实际上,Go 标准库的要求比 Go readability 的要求要高,比如 http://tip.golang.org/cmd/pprof/internal/
是通过 Go readability review 的,但是这个包是不符合 Go 标准库的要求的 [一个问题是每个包太小了]。)

就算是单独用的数据结构,并发安全的数据结构也不意味着你在用的时候不需要再考虑并发安全。

最简单的例子是,我有俩 lock-free 的堆栈,我想把一个的头移动到另一个头,但是我的应用要求,这个过程
必须是原子操作。简单说就是对于并发的访问,被移动的数据不能丢(要么在第一个堆栈,要么在第二个)。
这种情况下,即使你的堆栈是并发安全的,你还是需要仔细考虑如何做到这个操作并发安全,这也是为啥虽然
Lock-free 的数据结构在高并发下的可扩展性 (scalability) 非常好,但是使用并不像使用锁的数据结构那么普遍
的原因。并发编程的可组合性(composability)非常差,每个子对象具有特性 P,但是并不意味着他们的组合
也具有 P(事务内存 [Transactional Memory] 就是试图解决这个问题,如何让你随意地通过加锁来保证安全,
但是却不需要显式地指定用锁什么,由处理器或者STM的软件实现根据临界区 [critical section] 里面读取和写入
的内存地址来决定如何保证互斥)。你组合了之后还是需要从你的应用的需求角度考虑如何是否需要整体具有
特性 P,以及如何保证特性 P。

这些因素都不是说使用了并发安全的数据结构(甚至 lock-free 的)就不需要考虑的。

Go 1.4 的内存模型(http://tip.golang.org/ref/mem)加了一个改动,翻译过来就是:
"应该使用 channel 操作或者 sync, sync/atomic 包保证你的程序的并发安全。
如果你需要阅读这篇文档才能知道你的程序是否正确,你就是太聪明了(too clever)。
不要自作聪明。"

Philo Yang

unread,
Dec 7, 2014, 1:22:54 PM12/7/14
to golang...@googlegroups.com
我觉得关键还是个理念问题吧。一部分gopher是把go当做“一个更好用的xx”,xx代表他之前用的语言或一些常用语言,那么自然是希望除了go自己好用的部分之外也至少提供与其他语言一致或类似或接近的功能/自带的库,毕竟加一个功能也不会影响现有的东西。而另一些人会觉得引入某些功能/库会破坏整体设计理念于是坚持(至少暂时)不把某个东西引入到go。

至于具体到关于并发容器的讨论,虽然说可以很容易的引用第三方实现的库来用,但其实大家并不了解一个实现是否靠谱,如果有类似java中的guava这种比较靠谱、权威、大家都在用的实用库的合集,那些功能到底是否被收编成标准库似乎也不那么重要了?

Thanks,
Philo Yang


--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
---
您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/CAFK4q9zxPpMEU3%2B%3D%3DC6n9nBZyUNMttfUUw%3DipJHsVyN032tHqg%40mail.gmail.com
要查看更多选项,请访问https://groups.google.com/d/optout

hyper-carrot

unread,
Dec 7, 2014, 7:52:55 PM12/7/14
to golang...@googlegroups.com
我同意Yang的说法。

楚杰,我的意思也是:如果有一个权威的、靠谱的并发安全容器(或者其他)的函数库的话,应该是Go语言爱好者的一个福音。

说到具体的例子,比如并发安全的容器(字典、列表、队列等等),goroutine barrier (从 thread barrier想到的这个词,当然,这种语义可以使用channel来模拟),等等。

另外,Yang,我并没有把Go语言当做“更好用的xx”来看待。Go就是Go,她显然融合了各种优势,没有必要那样横向去比较。我只希望Go语言更好,并且更流行。还是那句话,既然Go提供了传统的同步工具,那么这方面能够得到深化很可能会带来更多的好处。对于Gopher来讲,选择更多了。对于Go语言来讲,更易推广。

发扬传统同步方式不是 golang style,这点我认同。不管我认为可以用的那个“扩展的并发库”出自谁之手,我觉得都会起到积极的作用。



在 2014年12月8日星期一UTC+8上午2时22分54秒,Philo Yang写道:

Thanks,
Philo Yang


要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china+unsubscribe@googlegroups.com

hyper-carrot

unread,
Dec 7, 2014, 8:05:27 PM12/7/14
to golang...@googlegroups.com

嗯,是这样。所以我一直在强调“扩充”、“扩展”,是多一种选择,而不是替换和必须。所有的通用型工具都会面临“太通用以至于不符合现有场景”的问题。但是这里说的特殊的“现有场景”并不是全部,终归会有相当一部分场景是相似的,是可以直接使用这些工具的。当然,如果没有,开发者很有可能去自己搞出一个来。这不就是轮子吗。另外,在“现有场景”下,开发者肯定就不会使用这些通用工具了,他们会自己搞,正如你举的例子所说。

就像Yang说的那样,也许会有个权威、可靠的第三方库问世。这样也不错。

在 2014年12月7日星期日UTC+8上午4时41分22秒,minux写道:

Leo Liu

unread,
Dec 7, 2014, 8:31:07 PM12/7/14
to golang...@googlegroups.com

minux 的意思大约是,弄出这样一个库来,不会带来真正的好处,但可能把一些事情搞砸。

 

发件人: golang...@googlegroups.com [mailto:golang...@googlegroups.com] 代表 hyper-carrot
发送时间: 2014128 9:05
收件人: golang...@googlegroups.com
主题: Re: [gocn:12761] Re: go标准库container支持multi goroutine吗?

--
--

官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
---
您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。

要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com
要在网络上查看此讨论,请访问https://groups.google.com/d/msgid/golang-china/454ae9d6-a512-42cd-9f68-8560686246b2%40googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

mikespook

unread,
Dec 7, 2014, 10:03:38 PM12/7/14
to golang中文组 golang中文组
Go 问世这么多年来,类似的第三方库其实出现了很多。至于为什么没有一个 @hyper-carrot 觉得权威且可靠的库,我个人观点认为,由于大家对这个方面的需求差异很大,合适 A 情况的,B 用不了,兼容 AB 的,C 又会有问题。最后,这个“安全”、“通用”的库就陷入一种取舍困境之中了。这个问题,@Monnand 和 @minux 都从不同角度进行了解释。那我从实践的角度来提点建议吧:

首先,从严格意义上说 Java 标准库也并不是一套库来适配所有场景,J2EE、J2ME……众多标准,许多情况下,标准库真得只是一个标准,实际的实现千差万别。更具体一些,一些并发数据结构(例如 ConcurrentHashMap 是在 HashMap 基础上实现 ConcurrentMap )实际上只是一个子接口。那么大多数实际场景如果真得仔细设计,例如在 HashMap 不适用的时候,还是得自己实现。只是有一个统一的接口(ConcurrentContainer 如何?)。

那么大家都知道, Go 的这个叫做接口的东西跟 Java 中的接口在设计思路上是完全不同的。所以在 Go 项目中自己定义一个接口(ConcurrentContainer),然后用不同的底层逻辑(map, list, ring...)来实现并发数据结构,现有状况下是比较理想的方法。

那么,如果这个设计和封装做得很好,能够满足大量人的需求,就会有大量的用户在自己的项目中使用的时候,这就会成为事实上的一个标准库。而如果这个东西怎么搞都还只能满足一部分人的话,就没必要放标准库了。

根据上面的流程,我反而觉得如果已经有这方面需求,可以提取开源出来。毕竟权威不权威、可靠不可靠得看实践。

PS:像 Java 提供的那个 ConcurrentHashMap 我觉得不像是让大家直接拿来用的,倒是更像演示如何使用 ConcurrentMap 这个接口的示例代码。至少,除了在学校的作业,和一些不怎么重要的项目中使用过,其他场景似乎都还是以自己设计一个数据结构来实现 ConcurrentMap 接口为主。

--
--
官网: http://golang-china.org/
IRC: irc.freenode.net #golang-china
@golangchina
---
您收到此邮件是因为您订阅了Google网上论坛中的“Golang-China”论坛。
要退订此论坛并停止接收此论坛的电子邮件,请发送电子邮件到golang-china...@googlegroups.com



--
Xing Xing (邢星)
mikespook <mike...@gmail.com>
http://mikespook.com

Philo Yang

unread,
Dec 8, 2014, 1:03:44 AM12/8/14
to golang...@googlegroups.com
java的并发容器可不只是ConcurrentHashMap,类似java6中加入的ConcurrentSkipListMap几乎可以说它是“java里唯一能在生产环境里用的Lock Free的SkipList实现”,Cassandra、Hbase之类的数据库都是直接拿来用的。

Thanks,
Philo Yang


Philo Yang

unread,
Dec 8, 2014, 1:07:27 AM12/8/14
to golang...@googlegroups.com
至于说go的官方并发容器库,我个人倒是不那么急,似乎先支持泛型之后再搞提供各种官方容器更好:)

Thanks,
Philo Yang

Reply all
Reply to author
Forward
0 new messages