Responda a essas perguntas antes de enviar seu problema. Obrigado!
go version
)?Go 1.7.5, 1.8 rc3 e git
go env
)?Arch Linux 64 bits
go run
https://gist.github.com/OneOfOne/4d7e13977886ddab825870bc3422a901
trocar de terminais e executar wrk -c 20 -d 30s http://localhost:8081
Mesma taxa de transferência de 1,7 ou mais rápido.
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
Tarde demais para o Go 1.8, mas podemos analisar o desempenho durante o Go 1.9.
Alguém quer investigar a diferença? O que um perfil de CPU Go 1.7 vs Go 1.8 diz?
Jogo atualizado com pprof: https://play.golang.org/p/GZ4zQOg1Wf
Executei go tool pprof http://localhost:6060/debug/pprof/profile
, troquei os termos e executei 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
Deixe-me saber se você quiser que eu faça algo específico.
Ai, estou vendo a mesma coisa com cerca de 20% de lentidão no benchmark do meu servidor da web com 1.8r3 e um tamanho binário um pouco maior também
Sei que está atrasado no ciclo de lançamento, mas a regressão de 20% no http é uma regressão enorme para muitas pessoas.
Estou disposto a ajudar a depurar se você me disser o que é necessário @bradfitz.
Estou disposto a ajudar a depurar se você me disser o que é necessário @bradfitz.
A etapa 1 é depurar por que ficou mais lento. Se você encontrar alguma pista, me avise.
@OneOfOne como isso funciona para aplicativos não-hello world? Você vê algum problema aí? Talvez 20% para aplicativos Hello World seja aceitável até 1.9?
@bradfitz Acho que o recurso de Shutdown
está causando desempenho inferior para o tipo de aplicativos / testes 'hello world'.
select {
case <-srv.getDoneChan():
return ErrServerClosed
//....
Olhe aqui .
Em 1,7 era apenas um loop de for
.
Alguém pode confirmar minha suposição?
Obrigado,
kataras
Não consigo reproduzir os resultados do OP. Estou em um Mac e estou usando versões _ um pouco_ mais antigas do 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
Há uma pequena diferença, mas é menor que 20%, quase insignificante aqui.
@kataras , você tem evidências a favor dessa teoria?
Você mesmo pode confirmar: exclua essas linhas e meça novamente.
Eu ficaria surpreso, no entanto.
@kataras Parece que provavelmente é isso. Além do select, você tem uma aquisição mutex e um desbloqueio que é feito em um adiamento (que eu sei que recentemente foi acelerado, mas ainda é um pouco mais lento do que um desbloqueio direto.
func (s *Server) getDoneChan() <-chan struct{} {
s.mu.Lock()
defer s.mu.Unlock()
return s.getDoneChanLocked()
}
Visto que o loop de aceitação é um caminho muito ativo, pode valer a pena mover a seleção de desligamento para uma goroutina separada e usar sync / atômico para sinalizar o desligamento no loop de aceitação.
EDITAR:
Acho que não é só isso, tentei apenas o tip sem o select e adiciona cerca de 7us (5% ~).
Eu entendo que é tarde demais para 1.8, mas por que não consertar isso em uma versão 1.8.1 futura?
Alguém mais foi capaz de reproduzir esses resultados?
-11,2% no Debian 8, amd64 (1.7.5 e rc3)
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 A implementação está correta, o que significa que o autor foi cuidadoso .. não é grande coisa bugs acontecem em software.
Dito isso, eu estava errado de qualquer maneira, olhei novamente agora há pouco e percebi que o select só acontece quando ocorre um erro durante a aceitação. O que é estranho é como meu programa fica mais lento de forma consistente quando o removo da aceitação. Talvez isso desqualifique aquele bloco de alguns passes de otimização ou inlining? Pode haver um problema em algum lugar causando lentidão, mas está em outro lugar e precisa de uma configuração diferente da minha.
@bradfitz Divisou isso
@codido , obrigado pela
Nunca fiz benchmarking (ou otimizações) depois dessa mudança.
Podemos analisá-lo para o Go 1.9.
Oi @bradfitz
Apenas uma pergunta rápida de alguém de fora, então, por favor, tenha paciência se eu perdi algo óbvio.
Por que seria tarde demais para corrigir esse problema? Não é essa a razão para candidatos a lançamento? Para encontrar os principais problemas finais antes de lançar a próxima versão principal?
Se não, por favor, me eduque.
Além disso, obrigado por trabalhar neste projeto, conheço muitas pessoas que amam esse idioma e a comunidade ao seu redor. 🎉
Por que as pessoas estão respondendo e votando como se esse fosse um problema importante? Essa mudança parece ter um impacto de desempenho no pior caso de aproximadamente 40 us por solicitação. Isso soa muito baixo para mim, há um cenário do mundo real onde isso importaria?
(editar: eu estava errado, é ~ 0,5us por solicitação, então ainda mais baixo)
Acho que pode ser necessário haver mais benchmarks em torno disso para ver o efeito em outras coisas além do hello world. Coisas como hello world colocam muita pressão de benchmark nas partes internas e, como tal, podem ampliar os efeitos da lentidão. Em um aplicativo do mundo real, há um carregamento de mais código executado, o que, em teoria, torna o efeito de coisas como essa muito menor por solicitação - ou seja, torna-se menos de uma% por solicitação, o que significa que o efeito é reduzido.
Apenas meus 2 centavos.
(Vou examinar precisamente isso mais tarde, se tiver tempo)
@reimertz Lembro-me de ter lido sobre o ciclo de lançamento aqui: https://github.com/golang/go/wiki/Go-Release-Cycle
Depois que um candidato a lançamento é emitido, apenas alterações na documentação e alterações para resolver bugs críticos devem ser feitas. Em geral, a barra para correções de bugs neste ponto é ainda um pouco mais alta do que a barra para correções de bugs em uma versão menor. Podemos preferir lançar um lançamento com uma falha conhecida, mas muito rara, do que lançar um lançamento com uma correção nova, mas não testada em produção.
Um dos critérios para a emissão de um candidato a lançamento é que o Google use essa versão do código para novas compilações de produção por padrão: se nós do Google não estamos dispostos a executá-lo para uso em produção, não deveríamos pedir a outros.
@kmlx obrigado pelo link! Eu só fui aqui: https://golang.org/doc/contribute.html e procurei por 'release' e não consegui encontrar nada. Foi mal.
Além disso, uau! Se o Google vai executar esta versão em seus servidores de produção e está tudo bem com um impacto de desempenho de pior caso de ~ 40us por solicitação (citando @tinco ), acho que o resto do mundo pode também. 🙂
É por isso que pedimos às pessoas que testem as versões beta. Para que, se acreditarem que encontraram um problema, possam reclamar o quanto antes.
go1.8beta1 foi lançado em 1 de dezembro de 2016 , há mais de 2 meses:
https://groups.google.com/d/topic/golang-nuts/QYuo0fai6YE/discussion
Citando o anúncio:
É importante encontrarmos bugs antes de emitir um candidato a lançamento.
O candidato a lançamento está previsto para a primeira semana de janeiro.
Sua ajuda no teste deste beta é inestimável.
Desculpe, olhei para os números errados. Portanto, no teste de go tip
fez 5110713 solicitações em 30 segundos, ou seja, 5,87 us por solicitação. Go 1.7.5 fez 5631803 solicitações em 30 segundos, 5,33 us por solicitação. Então, quando você os compara, é uma diminuição de 11% no desempenho. Mas se você olhar de uma perspectiva absoluta, é um impacto de desempenho de apenas meio microssegundo por solicitação. Não consigo nem imaginar um serviço HTTP onde isso seja relevante.
@tinco eu concordo, é uma regressão muito pequena quando colocada em perspectiva. No entanto, ainda é muito importante descobrir por que ele regrediu. A menos que você queira uma situação como: # 6853 e Go 1.9 vem com outra redução de 11%.
Dito isso, não sei por que isso não pode ser corrigido com um lançamento de patch (em vez de um lançamento menor).
@tinco , quantos núcleos esse computador tem? multiplique 0,5us pelo número de núcleos.
Na quarta-feira, 8 de fevereiro de 2017 às 4:13 PM, Sokolov Yura [email protected]
escrevi:
quantos núcleos esse computador tem? multiplique 0,5us pelo número de núcleos.
Por que o número de núcleos tem a ver com isso.
cada solicitação é tratada apenas por um único núcleo.
@minux, os 5 milhões de pedidos são tratados em 30 segundos por N núcleos. Portanto, o tempo real gasto por solicitação em cada núcleo é 30 / 5M * N. N é provavelmente bastante pequeno, menos de 10 provavelmente, então não é realmente relevante.
Versões menores são para bugs críticos e inevitáveis. Seu programa tem 1% de chance de falhar aleatoriamente após um dia de execução é o tipo de bug que corrigimos em um lançamento pontual, com a correção mais simples, segura e trivial possível. Versões menores não são para consertar "seu programa roda 0,5us mais devagar para executar uma operação que provavelmente leva muito mais tempo do que o geral".
Eu acho que você está se referindo a lançamentos de patch ( 1.8.x
) vs menores ( 1.x.0
).
IMO, todo o objetivo dos lançamentos de patch era lidar com regressões sem alterar recursos ou qualquer comportamento. Considerando que este não parece um grande problema, não vejo razão para não corrigi-lo em um 1.8.patch
.
No projeto Go, nos referimos a 1.x como uma versão principal e 1.xy como uma versão secundária (ou às vezes pontual): Go 1.8 é uma versão principal; Go 1.8.2 é uma versão secundária ou pontual. Não faz sentido chamar o Go 1.8 de um lançamento menor.
A política de lançamento do projeto Go está documentada em https://golang.org/doc/devel/release.html#policy :
Cada versão principal do Go torna obsoleta e encerra o suporte para a anterior. Por exemplo, se Go 1.5 foi lançado, então é a versão atual e Go 1.4 e anteriores não são mais suportados. Corrigimos problemas críticos na versão atual conforme necessário, emitindo pequenas revisões (por exemplo, Go 1.5.1, Go 1.5.2 e assim por diante).
Go 1.5 é compatível com Go 1.4 com algumas ressalvas: seu código não deve depender de comportamento não documentado (por exemplo, a ordenação de elementos iguais escolhidos por sort.Sort), seu código deve usar literais de estrutura com chave para que não interromper se novos campos de estrutura forem adicionados e assim por diante .
Na medida do possível, o Go 1.5.1 é compatível com as versões anteriores do Go 1.5 sem quaisquer advertências: nosso objetivo é atualizar do Go 1.5 para o Go 1.5.1 para ser uma operação com segurança garantida, um não evento, como você diz " sem alterar recursos ou qualquer comportamento ".
Aceitar que cometer erros é uma parte inevitável da criação de software e que sempre que você fizer uma alteração, haverá o risco de introduzir um bug que não é detectado pelo teste antes do lançamento, a melhor maneira que conhecemos de reduzir esse risco é proibir mudanças não críticas em lançamentos pontuais.
Corrigir uma desaceleração de 0,5us que só aparece em microbenchmarks é uma mudança não crítica.
@tinco se não considerarmos esse problema de desempenho "chamado de menor" e toda vez que o ignorarmos,
@ rashidul0405 Este problema ainda está aberto; ninguém está ignorando isso. Eu estava explicando por que ele não merece uma correção apressada no Go 1.8 ou Go 1.8.1.
Eu aceitaria com prazer um Go 1% mais lento em vez de um Go 1% mais travado.
Vamos manter a discussão nas listas de e-mail e Twitter etc.
Por favor, apenas comente aqui se você estiver trabalhando neste problema.
Já que ninguém parece querer trabalhar nisso, vou fechá-lo. Não podemos perseguir todos os detalhes de desempenho possíveis, e este está ficando velho.
Comentários muito úteis
Oi @bradfitz
Apenas uma pergunta rápida de alguém de fora, então, por favor, tenha paciência se eu perdi algo óbvio.
Por que seria tarde demais para corrigir esse problema? Não é essa a razão para candidatos a lançamento? Para encontrar os principais problemas finais antes de lançar a próxima versão principal?
Se não, por favor, me eduque.
Além disso, obrigado por trabalhar neste projeto, conheço muitas pessoas que amam esse idioma e a comunidade ao seu redor. 🎉