分享
Golang中重新open 已经被close的chan管道
GoWKH · · 2824 次点击 · · 开始浏览这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
最近忽发奇想,在Golang中怎么把,已经关闭的管道再次打开。这样就避免了,每次都要make一个新的chan,节省内存申请和GC的时间,查看go的源代码,经过简单地摸索后,实现了,示例代码如下。
func TestUnsafe(t *testing.T) {
c1 = make(chan struct{}, 10)
c1 <- struct{}{}
<-c1
close(c1)
p := (*unsafe.Pointer)(unsafe.Pointer(&c1))
c := (*hchan)(*p)
c.closed = 0//打开被关闭的chan
c1 <- struct{}{}
<-c1
}
func TestSafe(t *testing.T) {
c1 = make(chan struct{}, 10)
c1 <- struct{}{}
<-c1
close(c1)
p := (*unsafe.Pointer)(unsafe.Pointer(&c1))
c := (*hchan)(*p)
atomic.CompareAndSwapUint32(&c.closed, 1, 0) //打开被关闭的chan
c1 <- struct{}{}
<-c1
}
最终代码 发布到 github.com/yireyun/go-openc,有兴趣的朋友可以看看。
这种做法最大的缺点是如果go的runtime的数据结构发生变化,将不再可行。因此增加了在init方法中检测的go内核数据结构是否发生变化的代码,性能测试结果如下。
BenchmarkMakeCloseChan-4 20000000 90.9 ns/op
--- BENCH: BenchmarkMakeCloseChan-4(每次新建在关闭的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 998.3μs 99ns/op
go1.7.4, Times: 1000000, use: 91.0664ms 91ns/op
go1.7.4, Times: 20000000, use: 1.8185449s 90ns/op
BenchmarkCloseOpenChan-4 50000000 29.5 ns/op
--- BENCH: BenchmarkCloseOpenChan-4(非安全打开的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 0s 0s/op
go1.7.4, Times: 1000000, use: 28.5199ms 28ns/op
go1.7.4, Times: 50000000, use: 1.473497s 29ns/op
BenchmarkCloseOpenChanSync-4 30000000 44.9 ns/op
--- BENCH: BenchmarkCloseOpenChanSync-4(安全打开的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 498.2μs 49ns/op
go1.7.4, Times: 1000000, use: 47.5278ms 47ns/op
go1.7.4, Times: 30000000, use: 1.3479236s 44ns/op
PASS
ok github.com/yireyun/go-openc 8.235s
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信2824 次点击
上一篇:Golang 介绍及踩坑系列之三
下一篇:以太坊常用网址
添加一条新回复
(您需要 后才能回复 没有账号 ?)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
func TestUnsafe(t *testing.T) {
c1 = make(chan struct{}, 10)
c1 <- struct{}{}
<-c1
close(c1)
p := (*unsafe.Pointer)(unsafe.Pointer(&c1))
c := (*hchan)(*p)
c.closed = 0//打开被关闭的chan
c1 <- struct{}{}
<-c1
}
func TestSafe(t *testing.T) {
c1 = make(chan struct{}, 10)
c1 <- struct{}{}
<-c1
close(c1)
p := (*unsafe.Pointer)(unsafe.Pointer(&c1))
c := (*hchan)(*p)
atomic.CompareAndSwapUint32(&c.closed, 1, 0) //打开被关闭的chan
c1 <- struct{}{}
<-c1
}
最终代码 发布到 github.com/yireyun/go-openc,有兴趣的朋友可以看看。
这种做法最大的缺点是如果go的runtime的数据结构发生变化,将不再可行。因此增加了在init方法中检测的go内核数据结构是否发生变化的代码,性能测试结果如下。
BenchmarkMakeCloseChan-4 20000000 90.9 ns/op
--- BENCH: BenchmarkMakeCloseChan-4(每次新建在关闭的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 998.3μs 99ns/op
go1.7.4, Times: 1000000, use: 91.0664ms 91ns/op
go1.7.4, Times: 20000000, use: 1.8185449s 90ns/op
BenchmarkCloseOpenChan-4 50000000 29.5 ns/op
--- BENCH: BenchmarkCloseOpenChan-4(非安全打开的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 0s 0s/op
go1.7.4, Times: 1000000, use: 28.5199ms 28ns/op
go1.7.4, Times: 50000000, use: 1.473497s 29ns/op
BenchmarkCloseOpenChanSync-4 30000000 44.9 ns/op
--- BENCH: BenchmarkCloseOpenChanSync-4(安全打开的性能)
go1.7.4, Times: 1, use: 0s 0s/op
go1.7.4, Times: 100, use: 0s 0s/op
go1.7.4, Times: 10000, use: 498.2μs 49ns/op
go1.7.4, Times: 1000000, use: 47.5278ms 47ns/op
go1.7.4, Times: 30000000, use: 1.3479236s 44ns/op
PASS
ok github.com/yireyun/go-openc 8.235s