在提交问题之前,请先回答这些问题。 谢谢!
go version
)?去1.7.5、1.8 rc3和git
go env
)?Arch Linux 64位
go run
https://gist.github.com/OneOfOne/4d7e13977886ddab825870bc3422a901
切换终端并运行wrk -c 20 -d 30s http://localhost:8081
吞吐量等于1.7或更快。
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 195.30us 470.12us 16.30ms 95.11%
Req/Sec 85.62k 6.00k 95.21k 80.83%
5110713 requests in 30.01s, 721.35MB read
Requests/sec: 170322.67
Transfer/sec: 24.04MB
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 192.49us 451.74us 15.14ms 95.02%
Req/Sec 85.91k 6.37k 97.60k 83.50%
5130079 requests in 30.01s, 724.08MB read
Requests/sec: 170941.23
Transfer/sec: 24.13MB
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 210.16us 528.53us 14.78ms 94.13%
Req/Sec 94.34k 4.31k 103.56k 73.83%
5631803 requests in 30.01s, 794.89MB read
Requests/sec: 187673.03
Transfer/sec: 26.49MB
对于Go 1.8来说为时已晚,但是我们可以研究Go 1.9期间的性能。
有人想调查差异吗? Go 1.7 vs Go 1.8 CPU配置文件是什么?
使用pprof更新了播放: https :
我运行了go tool pprof http://localhost:6060/debug/pprof/profile
,更改了条款并运行了wrk -c 20 -d 30s http://localhost:6060/
。
(pprof) top
36600ms of 80000ms total (45.75%)
Dropped 297 nodes (cum <= 400ms)
Showing top 10 nodes out of 135 (cum >= 970ms)
flat flat% sum% cum cum%
26360ms 32.95% 32.95% 27340ms 34.17% syscall.Syscall
2280ms 2.85% 35.80% 5740ms 7.17% runtime.mallocgc
1310ms 1.64% 37.44% 1310ms 1.64% runtime.heapBitsSetType
1260ms 1.57% 39.01% 1260ms 1.57% runtime._ExternalCode
1030ms 1.29% 40.30% 7280ms 9.10% net/http.(*chunkWriter).writeHeader
970ms 1.21% 41.51% 970ms 1.21% runtime.epollwait
900ms 1.12% 42.64% 920ms 1.15% runtime.mapiternext
880ms 1.10% 43.74% 880ms 1.10% runtime.usleep
820ms 1.03% 44.76% 1490ms 1.86% runtime.deferreturn
790ms 0.99% 45.75% 970ms 1.21% runtime.mapaccess1_faststr
(pprof) top -cum
27.89s of 80s total (34.86%)
Dropped 297 nodes (cum <= 0.40s)
Showing top 10 nodes out of 135 (cum >= 23.44s)
flat flat% sum% cum cum%
0.01s 0.013% 0.013% 73.46s 91.83% runtime.goexit
0.55s 0.69% 0.7% 69.55s 86.94% net/http.(*conn).serve
0.30s 0.38% 1.07% 35.91s 44.89% net/http.(*response).finishRequest
0.15s 0.19% 1.26% 32.10s 40.12% bufio.(*Writer).Flush
26.36s 32.95% 34.21% 27.34s 34.17% syscall.Syscall
0.10s 0.12% 34.34% 24.56s 30.70% net/http.checkConnErrorWriter.Write
0 0% 34.34% 24.44s 30.55% net.(*conn).Write
0.23s 0.29% 34.62% 24.44s 30.55% net.(*netFD).Write
0.06s 0.075% 34.70% 23.50s 29.38% syscall.Write
0.13s 0.16% 34.86% 23.44s 29.30% syscall.write
(pprof) top
40520ms of 82240ms total (49.27%)
Dropped 281 nodes (cum <= 411.20ms)
Showing top 10 nodes out of 128 (cum >= 860ms)
flat flat% sum% cum cum%
29480ms 35.85% 35.85% 30920ms 37.60% syscall.Syscall
2550ms 3.10% 38.95% 5710ms 6.94% runtime.mallocgc
1560ms 1.90% 40.84% 1590ms 1.93% runtime.heapBitsSetType
1220ms 1.48% 42.33% 1220ms 1.48% runtime.epollwait
1050ms 1.28% 43.60% 2750ms 3.34% runtime.mapassign1
1050ms 1.28% 44.88% 1080ms 1.31% runtime.mapiternext
1000ms 1.22% 46.10% 7890ms 9.59% net/http.(*chunkWriter).writeHeader
880ms 1.07% 47.17% 2910ms 3.54% net/http.DetectContentType
870ms 1.06% 48.22% 1010ms 1.23% runtime.mapaccess1_faststr
860ms 1.05% 49.27% 860ms 1.05% runtime.futex
(pprof) top -cum
31.67s of 82.24s total (38.51%)
Dropped 281 nodes (cum <= 0.41s)
Showing top 10 nodes out of 128 (cum >= 27.69s)
flat flat% sum% cum cum%
0 0% 0% 75.77s 92.13% runtime.goexit
0.44s 0.54% 0.54% 74.26s 90.30% net/http.(*conn).serve
0.27s 0.33% 0.86% 37.08s 45.09% net/http.(*response).finishRequest
0.18s 0.22% 1.08% 36.44s 44.31% bufio.(*Writer).Flush
0.25s 0.3% 1.39% 36.26s 44.09% bufio.(*Writer).flush
29.48s 35.85% 37.23% 30.92s 37.60% syscall.Syscall
0.12s 0.15% 37.38% 27.99s 34.03% net/http.checkConnErrorWriter.Write
0.69s 0.84% 38.22% 27.85s 33.86% net/http.(*conn).readRequest
0.08s 0.097% 38.31% 27.77s 33.77% net.(*conn).Write
0.16s 0.19% 38.51% 27.69s 33.67% net.(*netFD).Write
让我知道您是否要我做任何具体的事情。
哎呀,我看到的是同一件事,在使用1.8r3的网络服务器基准测试中,速度降低了约20%,二进制文件的大小也略有增加
我意识到发布周期很晚,但是对许多人来说,http的20%回归是一个巨大的回归。
如果您告诉我需要什么@bradfitz,我愿意帮助调试。
如果您告诉我需要什么@bradfitz,我愿意帮助调试。
步骤1是调试为什么变慢。 如果您有任何线索,请告诉我。
@OneOfOne对于非Hello World应用程序如何工作? 您在那看到任何问题吗? 直到1.9为止,您都可以接受Hello World应用程序的20%吗?
@bradfitz我认为Shutdown
功能导致“ hello world”应用/测试的性能下降。
select {
case <-srv.getDoneChan():
return ErrServerClosed
//....
看这里。
在1.7,它只是一个for
循环。
有人可以确认我的假设吗?
谢谢,
卡塔拉斯
我无法复制OP的结果。 我在Mac上,并且正在使用_slightly_旧版本的Go。
$ wrk -c 20 -d 30s http://localhost:8081 # go 1.8 RC2
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 0.87ms 6.99ms 151.45ms 99.38%
Req/Sec 25.22k 2.34k 33.28k 66.94%
1510655 requests in 30.10s, 213.22MB read
Requests/sec: 50188.34
Transfer/sec: 7.08MB
$ wrk -c 20 -d 30s http://localhost:8081 # go 1.7.4
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 840.73us 6.85ms 151.46ms 99.41%
Req/Sec 26.05k 3.67k 33.43k 60.96%
1560770 requests in 30.10s, 220.29MB read
Requests/sec: 51853.50
Transfer/sec: 7.32MB
略有差异,但小于20%,在这里几乎可以忽略不计。
@kataras ,您是否有证据支持该理论?
您可以自己确认:删除这些行并再次进行测量。
不过,我会感到惊讶。
@kataras看起来可能就是这样。 除了选择之外,您还具有互斥锁获取和延迟执行的解锁(我知道这最近有所加快,但是比直接解锁要慢一些)。
func (s *Server) getDoneChan() <-chan struct{} {
s.mu.Lock()
defer s.mu.Unlock()
return s.getDoneChanLocked()
}
由于accept循环是一条很热的路径,因此有必要将关闭选择移到一个单独的goroutine中,并使用sync / atomic在accept循环中发出关闭信号。
编辑:
我不认为这就是这样,只是尝试了一次小费而没有全部选择的技巧,它增加了大约7us(5%〜)。
我知道这对于1.8来说为时已晚,但是为什么不在以后的1.8.1版本中解决此问题呢?
还有其他人能够重现这些结果吗?
Debian 8,amd64(1.7.5和rc3)的-11.2%
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 457.65us 1.26ms 46.74ms 93.23%
Req/Sec 65.08k 7.84k 99.65k 73.83%
3891443 requests in 30.07s, 549.25MB read
Requests/sec: 129397.13
Transfer/sec: 18.26MB
Running 30s test @ http://localhost:8081
2 threads and 20 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 350.93us 0.92ms 39.50ms 94.72%
Req/Sec 57.70k 5.34k 77.31k 74.50%
3447358 requests in 30.03s, 486.57MB read
Requests/sec: 114800.24
Transfer/sec: 16.20MB
@kataras实现是正确的,这意味着作者很小心..在软件中发生的错误并不是很多。
就是说我还是错了,我刚才又看了一眼,发现选择仅在接受期间发生错误时才发生。 奇怪的是,当我从接受中删除程序时,它如何始终使我的程序变慢。 也许它取消了某些优化通过或内联的限制? 在某处可能会导致速度下降的问题,但在其他地方,需要的设置与我的不同。
@bradfitz简要地将
@codido ,感谢您的平分! 是的,这也是我也会怀疑的承诺。 很高兴看到确认。 这是一段时间以来net / http.Server中最大的体系结构更改之一。
更改之后,我再也没有进行任何基准测试(或优化)。
我们可以在Go 1.9中研究它。
嗨@bradfitz
只是局外人的一个简短问题,所以如果我错过了明显的事情,请忍受我。
为什么解决这个问题为时已晚? 这不是释放候选人的全部理由吗? 要在发布下一个主要版本之前找到最终的主要问题?
如果没有,请教育我。
另外,感谢您为这个项目所做的工作,我认识许多人喜欢这种语言以及周围的社区。 🎉
人们为什么要回应和投票,好像这是一个主要问题? 对于每个请求,此更改似乎对最坏情况的性能影响约为40us。 这对我来说听起来很低,在现实世界中有什么要紧的吗?
(编辑:我错了,每个请求约0.5us,所以甚至更低)
我认为可能需要围绕此问题制定更多基准,以了解对世界以外的其他事物的影响。 诸如hello world之类的事情对内部构件施加了很多基准压力,因此可以放大减速的影响。 在现实世界的应用程序中,运行着更多的代码,从理论上讲,这样的效果使每个请求的效果大大减小-即,每个请求的效果降低了%,这意味着效果降低了。
只是我的2美分。
(如果有时间的话,我稍后会详细介绍)
@reimertz我记得在这里阅读过有关发布周期的信息: https :
发布候选版本后,仅应进行文档更改和更改以解决严重的错误。 通常,此时的错误修复标准甚至比次要版本中的错误修复标准稍高。 与发布具有新但未经生产测试的修复程序相比,我们可能更喜欢发布具有已知但非常罕见的崩溃的发布。
发行候选版本的标准之一是Google默认将该版本的代码用于新的生产版本:如果我们Google不愿意将其用于生产,则不应要求其他人使用。
@kmlx感谢您的链接! 我只去了这里: https :
还有,哇! 如果Google可以在其生产服务器上运行该版本,并且可以接受每个请求40us的最坏情况(引用@tinco ),那么我认为世界其他地区也可以。 🙂
这就是为什么我们要求人们测试Beta版本的原因。 这样一来,如果他们认为找到问题了,可以提早投诉。
go1.8beta1于2016年12月1日发布,超过2个月前:
https://groups.google.com/d/topic/golang-nuts/QYuo0fai6YE/discussion
引用公告:
在发布候选版本,这一点很重要。
候选版本计划于一月的第一周。
您在测试此Beta版方面的帮助非常宝贵。
对不起,我看错了数字。 因此,通过@OneOfOne的测试, go tip
在30秒内发出了5110713个请求,即每个请求5.87us。 Go 1.7.5在30秒内发出了5630803个请求,每个请求5.33us。 因此,将它们相互比较时,性能下降了11%。 但是,如果从绝对的角度来看它,那么每个请求的性能下降仅为半微秒。 我什至无法想象HTTP服务会在其中发挥作用。
@tinco我同意,从角度来看,这只是一个很小的回归。 但是,弄清楚它为什么会退化仍然非常重要。 除非您遇到以下情况,否则:#6853和Go 1.9会再降低11%。
话虽这么说,我不确定为什么不能通过补丁发布(相对于次要版本)来解决。
@tinco ,该计算机有多少个内核? 将0.5us乘以内核数。
2017年2月8日,星期三,4:13 PM,Sokolov Yura [email protected]
写道:
那台计算机有多少个核心? 将0.5us乘以内核数。
为什么内核数量与此有关。
每个请求仅由单个内核处理。
@minux 500万个请求在30秒内由N个内核处理。 因此,每个请求在每个核心上花费的实时时间为30 / 5M *N。N可能很小,可能少于10,因此这并不是很重要。
次要版本适用于严重的,不可避免的错误。 在一天的执行之后,您的程序就有1%的概率随机崩溃,这是我们在点发行版中修复的错误,它是最简单,最安全,最简单的修复。 次要发行版不是用于解决“您的程序运行慢了0.5us才能执行可能比总时间长得多的操作”。
我猜您指的是修补程序版本( 1.8.x
)与次要版本( 1.x.0
)。
IMO发行补丁的全部目的是在不改变功能或任何行为的情况下解决回归问题。 尽管这看起来不大,但我认为没有理由不将其修复在1.8.patch
。
在Go项目中,我们将1.x称为主要版本,将1.xy称为次要(或有时是点)版本:Go 1.8是主要版本; Go 1.8.2是次要版本或点发行版本。 我们称Go 1.8为次要版本是没有意义的。
Go项目发布政策在https://golang.org/doc/devel/release.html#policy上有说明:
每个主要的Go版本均已过时,并终止了对前一个版本的支持。 例如,如果已经发布了Go 1.5,则它是当前版本,并且不再支持Go 1.4和更早版本。 我们会通过发布次要修订(例如,Go 1.5.1,Go 1.5.2等)来解决当前版本中的关键问题。
Go 1.5向后兼容Go 1.4,但有一些警告:您的代码不必依赖未记录的行为(例如,sort.Sort选择的相等元素的顺序),您的代码必须使用键控结构常量,因此它不会如果添加了新的struct字段则中断,等等。
尽最大可能,Go 1.5.1与Go 1.5向后兼容,没有任何此类警告:我们的目标是从Go 1.5升级到Go 1.5.1,以确保操作安全,这是非事件,如您所说:而不更改功能或任何行为”。
接受错误是编写软件不可避免的一部分,并且每当您进行更改时,就有风险会引入一个在发行前无法通过测试发现的错误,我们知道最好的降低风险的方法是禁止点释放的非关键更改。
修复仅在微基准测试中出现的0.5us减慢是一项非关键性的更改。
@tinco如果我们不考虑这个“所谓的次要”性能问题,并且每次我们忽略它,我们最终都会“走慢”。 IMO没有人希望这种情况发生。
@ rashidul0405这个问题仍然存在; 没有人会忽略它。 我在解释为什么它不值得匆忙修复到Go 1.8或Go 1.8.1中。
我很乐意将Go的速度降低1%,而不将速成的Go降低1%。
让我们继续讨论邮件列表和Twitter等。
如果您正在处理此问题,请仅在此处发表评论。
由于似乎没有人愿意对此进行处理,因此我将关闭它。 我们无法追踪所有可能的性能细节,而这个细节已经过时了。
最有用的评论
嗨@bradfitz
只是局外人的一个简短问题,所以如果我错过了明显的事情,请忍受我。
为什么解决这个问题为时已晚? 这不是释放候选人的全部理由吗? 要在发布下一个主要版本之前找到最终的主要问题?
如果没有,请教育我。
另外,感谢您为这个项目所做的工作,我认识许多人喜欢这种语言以及周围的社区。 🎉