Responda estas preguntas antes de enviar su problema. ¡Gracias!
go version
)?Ir a 1.7.5, 1.8 rc3 y git
go env
)?Arch Linux de 64 bits
go run
https://gist.github.com/OneOfOne/4d7e13977886ddab825870bc3422a901
cambiar terminales y ejecutar wrk -c 20 -d 30s http://localhost:8081
Mismo rendimiento que 1.7 o más 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
Demasiado tarde para Go 1.8, pero podemos analizar el rendimiento durante Go 1.9.
¿Alguien quiere investigar la diferencia? ¿Qué dice un perfil de CPU Go 1.7 vs Go 1.8?
Juego actualizado con pprof: https://play.golang.org/p/GZ4zQOg1Wf
Ejecuté go tool pprof http://localhost:6060/debug/pprof/profile
, cambié de términos y ejecuté 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
Avísame si quieres que haga algo específico.
Vaya, estoy viendo lo mismo con una ralentización de aproximadamente un 20% en el punto de referencia de mi servidor web con 1.8r3, y un tamaño binario ligeramente mayor también
Me doy cuenta de que es tarde en el ciclo de lanzamiento, pero la regresión del 20% en http es una gran regresión para mucha gente.
Estoy dispuesto a ayudar a depurar si me dice lo que se necesita @bradfitz.
Estoy dispuesto a ayudar a depurar si me dice lo que se necesita @bradfitz.
El paso 1 es depurar por qué se hizo más lento. Si encuentra alguna pista, hágamelo saber.
@OneOfOne ¿cómo funciona esto para aplicaciones que no son de Hello World? ¿Ves algún problema allí? ¿Quizás el 20% para las aplicaciones de Hello World sea aceptable hasta la 1.9?
@bradfitz Creo que la función de Shutdown
está provocando un rendimiento más bajo para el tipo de aplicaciones / pruebas de 'hola mundo'.
select {
case <-srv.getDoneChan():
return ErrServerClosed
//....
Mira aquí .
En 1.7 era solo un bucle for
.
¿Alguien puede confirmar mi suposición?
Gracias,
kataras
No puedo reproducir los resultados del OP. Estoy en una Mac y estoy usando _ligeramente_ versiones anteriores de 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
Hay una ligera diferencia, pero es menor al 20%, casi insignificante aquí.
@kataras , ¿tienes evidencia a favor de esa teoría?
Puede confirmarlo usted mismo: elimine esas líneas y vuelva a medir.
Sin embargo, me sorprendería.
@kataras Parece que probablemente lo sea. Además de la selección, tiene una adquisición de mutex y un desbloqueo que se realiza en un aplazamiento (que sé que se aceleró recientemente, pero aún son un poco más lentos que un desbloqueo directo.
func (s *Server) getDoneChan() <-chan struct{} {
s.mu.Lock()
defer s.mu.Unlock()
return s.getDoneChanLocked()
}
Dado que el ciclo de aceptación es una ruta tan activa, puede valer la pena mover la selección de apagado a una rutina de gor por separado y usar sincronización / atómico para señalar el cierre en el ciclo de aceptación.
EDITAR:
No creo que sea solo esto, solo probé la sugerencia sin seleccionar todos juntos y agrega aproximadamente 7us (5% ~).
Entiendo que es demasiado tarde para 1.8, pero ¿por qué no arreglarlo en una futura versión 1.8.1?
¿Alguien más ha podido reproducir estos resultados?
-11,2% en Debian 8, amd64 (1.7.5 y 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 La implementación es correcta, lo que significa que el autor fue cuidadoso ... no es que sucedan errores importantes en el software.
Dicho esto, estaba equivocado de todos modos, miré nuevamente y me di cuenta de que la selección solo ocurre cuando ocurre un error durante la aceptación. Lo extraño es cómo ralentizó mi programa constantemente cuando lo elimino de la aceptación. ¿Quizás descalifica a ese bloque de algunos pases de optimización o alineación? Puede haber un problema en algún lugar que cause una desaceleración, pero está en otro lugar y necesita una configuración diferente a la mía.
@bradfitz brevemente dividió esto, y parece que el commit faf882d1d427e8c8a9a1be00d8ddcab81d1e848e está causando al menos algo de esto. Veo un impacto de rendimiento de aproximadamente el 10% en este punto de referencia con este compromiso en comparación con el compromiso que lo precede.
@codido , gracias por el bisecto! Sí, y ese es el compromiso del que sospecharía también. Es bueno ver la confirmación. Ese fue uno de los mayores cambios arquitectónicos en net / http.Server en bastante tiempo.
Nunca realicé evaluaciones comparativas (u optimizaciones) después de ese cambio.
Podemos investigarlo para Go 1.9.
Hola @bradfitz
Solo una pregunta rápida de un forastero, así que tengan paciencia conmigo si me perdí algo obvio.
¿Por qué sería demasiado tarde para solucionar este problema? ¿No es esta la única razón para liberar a los candidatos? ¿Para encontrar los problemas principales finales antes de lanzar la próxima versión principal?
Si no es así, infórmame.
Además, gracias por trabajar en este proyecto, conozco a mucha gente que ama este idioma y la comunidad que lo rodea. 🎉
¿Por qué la gente responde y vota como si este fuera un problema importante? Este cambio parece tener un impacto en el rendimiento en el peor de los casos de ~ 40us por solicitud. Eso me suena muy bajo, ¿hay un escenario del mundo real en el que esto importe?
(editar: estaba equivocado, es ~ 0.5us por solicitud, así que aún más bajo)
Creo que podría necesitarse más puntos de referencia en torno a esto para ver el efecto en otras cosas además de hola mundo. Cosas como hola mundo ejercen una gran presión de referencia en los aspectos internos y, como tales, pueden magnificar los efectos de las ralentizaciones. En una aplicación del mundo real, hay una carga de más código que se ejecuta, lo que en teoría hace que el efecto de cosas como esta sea mucho más pequeño por solicitud, es decir, se reduce a un% por solicitud, lo que significa que el efecto se reduce.
Solo mis 2 centavos.
(Voy a ver precisamente esto más adelante si tengo tiempo)
@reimertz Recuerdo haber leído sobre el ciclo de lanzamiento aquí: https://github.com/golang/go/wiki/Go-Release-Cycle
Una vez que se emite una versión candidata, solo se deben realizar cambios en la documentación y los cambios para abordar los errores críticos. En general, la barra de corrección de errores en este punto es incluso ligeramente más alta que la barra de corrección de errores en una versión menor. Es posible que prefiramos emitir una versión con un bloqueo conocido pero muy poco común que emitir una versión con una solución nueva pero no probada en producción.
Uno de los criterios para emitir un candidato de lanzamiento es que Google use esa versión del código para nuevas compilaciones de producción de manera predeterminada: si en Google no estamos dispuestos a ejecutarlo para uso en producción, no deberíamos pedirle a otros que lo hagan.
@kmlx gracias por el enlace! Solo fui aquí: https://golang.org/doc/contribute.html y busqué 'lanzamiento' y no pude encontrar nada. Culpa mía.
Además, ¡guau! Si Google ejecuta esta versión en sus servidores de producción y está de acuerdo con un impacto de rendimiento en el peor de los casos de ~ 40us por solicitud (citando a @tinco ), supongo que el resto del mundo también puede
Es por eso que le pedimos a la gente que pruebe las versiones beta. De modo que si creen que han encontrado un problema, pueden quejarse temprano.
go1.8beta1 fue lanzado el 1 de diciembre de 2016 , hace más de 2 meses:
https://groups.google.com/d/topic/golang-nuts/QYuo0fai6YE/discussion
Citando el anuncio:
Es importante que encontremos errores antes de emitir una versión candidata.
La versión candidata está prevista para la primera semana de enero.
Su ayuda para probar esta versión beta es invaluable.
Lo siento, miré mal los números. Entonces, de la prueba de go tip
hizo 5110713 solicitudes en 30 segundos, eso es 5.87us por solicitud. Go 1.7.5 hizo 5631803 solicitudes en 30 segundos, 5.33us por solicitud. Entonces, cuando los compara entre sí, es como una disminución del rendimiento del 11%. Pero si lo mira desde una perspectiva absoluta, es un impacto de rendimiento de solo medio microsegundo por solicitud. Ni siquiera puedo imaginar un servicio HTTP donde esto sea relevante.
@tinco Estoy de acuerdo, es una regresión muy pequeña cuando se pone en perspectiva. Sin embargo, sigue siendo muy importante averiguar por qué retrocedió. A menos que desee una situación como: # 6853 y Go 1.9 aparece con otra disminución del 11%.
Dicho esto, no estoy seguro de por qué esto no se pudo solucionar con una versión de parche (frente a una versión menor).
@tinco , ¿cuántos núcleos tiene esa computadora? multiplique 0.5us por el número de núcleos.
El miércoles 8 de febrero de 2017 a las 4:13 p.m., Sokolov Yura [email protected]
escribió:
¿cuántos núcleos tiene esa computadora? multiplique 0.5us por el número de núcleos.
¿Por qué la cantidad de núcleos tiene que ver con esto?
cada solicitud solo es manejada por un único núcleo.
@minux los 5 millones de solicitudes se manejan en 30 segundos por N núcleos. Entonces, el tiempo real invertido por solicitud en cada núcleo es 30/5 M * N. N probablemente sea bastante pequeño, menos de 10 probablemente, por lo que no es realmente relevante.
Las versiones menores son para errores críticos e inevitables. Su programa tiene un 1% de probabilidad de fallar aleatoriamente después de un día de ejecución, es el tipo de error que corregimos en una versión puntual, con la solución más simple, segura y trivial posible. Las versiones menores no son para corregir "su programa corre 0.5us más lento para ejecutar una operación que probablemente demore mucho más que eso en general".
Supongo que te refieres a los lanzamientos de parches ( 1.8.x
) frente a los menores ( 1.x.0
).
En mi opinión, el objetivo de los lanzamientos de parches era abordar las regresiones sin cambiar las características ni ningún comportamiento. Si bien este no parece muy grande, no veo ninguna razón para no arreglarlo en un 1.8.patch
.
En el proyecto Go, nos referimos a 1.x como una versión principal y 1.xy como una versión menor (oa veces puntual): Go 1.8 es una versión principal; Go 1.8.2 es una versión menor o puntual. No tiene sentido que llamemos a Go 1.8 una versión menor.
La política de lanzamiento del proyecto Go está documentada en https://golang.org/doc/devel/release.html#policy :
Cada versión principal de Go queda obsoleta y finaliza el soporte de la anterior. Por ejemplo, si se lanzó Go 1.5, entonces es la versión actual y Go 1.4 y versiones anteriores ya no son compatibles. Solucionamos los problemas críticos en la versión actual según sea necesario mediante la publicación de revisiones menores (por ejemplo, Go 1.5.1, Go 1.5.2, etc.).
Go 1.5 es compatible con versiones anteriores de Go 1.4 con algunas advertencias: su código no debe depender de un comportamiento indocumentado (por ejemplo, el orden de elementos iguales elegidos por sort.Sort), su código debe usar literales de estructura con clave para que no lo haga romper si se agregan nuevos campos de estructura, y así sucesivamente .
En la mayor medida posible, Go 1.5.1 es retrocompatible con Go 1.5 sin tales advertencias: nuestro objetivo es que la actualización de Go 1.5 a Go 1.5.1 sea una operación segura garantizada, un no evento, como usted dice sin cambiar características ni ningún comportamiento ".
Aceptar que cometer errores es una parte inevitable de la escritura de software y que cada vez que realiza un cambio existe el riesgo de que introduzca un error que no se detecta mediante la prueba antes del lanzamiento, la mejor manera que conocemos de reducir ese riesgo es no permitir cambios no críticos en lanzamientos puntuales.
Arreglar una desaceleración de 0.5us que solo aparece en microbenchmarks es un cambio no crítico.
@tinco si no consideramos este problema de rendimiento "supuestamente menor" y cada vez que lo ignoramos, finalmente obtendremos "un proceso más lento". En mi opinión, nadie quiere que esto suceda.
@ rashidul0405 Este problema aún está abierto; nadie lo está ignorando. Estaba explicando por qué no merece una solución apresurada en Go 1.8 o Go 1.8.1.
Con mucho gusto tomaría un Go 1% más lento en lugar de un Go 1% más rápido.
Mantengamos la discusión sobre las listas de correo y Twitter, etc.
Solo comente aquí si está trabajando en este problema.
Como nadie parece querer trabajar en esto, lo cerraré. No podemos perseguir todos los detalles de rendimiento posibles, y este está envejeciendo.
Comentario más útil
Hola @bradfitz
Solo una pregunta rápida de un forastero, así que tengan paciencia conmigo si me perdí algo obvio.
¿Por qué sería demasiado tarde para solucionar este problema? ¿No es esta la única razón para liberar a los candidatos? ¿Para encontrar los problemas principales finales antes de lanzar la próxima versión principal?
Si no es así, infórmame.
Además, gracias por trabajar en este proyecto, conozco a mucha gente que ama este idioma y la comunidad que lo rodea. 🎉