Bitte beantworten Sie diese Fragen, bevor Sie Ihr Problem einreichen. Vielen Dank!
go version
)?Gehen Sie 1.7.5, 1.8 rc3 und git
go env
)?Arch Linux 64bit
go run
https://gist.github.com/OneOfOne/4d7e13977886ddab825870bc3422a901
Wechseln Sie die Terminals und führen Sie wrk -c 20 -d 30s http://localhost:8081
Gleicher Durchsatz wie 1,7 oder schneller.
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
Für Go 1.8 ist es zu spät, aber wir können die Leistung von Go 1.9 untersuchen.
Möchte jemand den Unterschied untersuchen? Was sagt ein Go 1.7 vs Go 1.8 CPU-Profil?
Aktualisiertes Spiel mit pprof: https://play.golang.org/p/GZ4zQOg1Wf
Ich habe go tool pprof http://localhost:6060/debug/pprof/profile
, die Begriffe gewechselt und 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
Lassen Sie mich wissen, ob ich etwas Bestimmtes tun soll.
Autsch, ich sehe dasselbe mit einer Verlangsamung meines Webserver-Benchmarks um 20% mit 1,8r3 und einer etwas größeren Binärgröße
Mir ist klar, dass es spät im Veröffentlichungszyklus ist, aber eine Regression von 20% auf http ist für viele Menschen eine enorme Regression.
Ich bin bereit, beim Debuggen zu helfen, wenn Sie mir sagen, was @bradfitz benötigt.
Ich bin bereit, beim Debuggen zu helfen, wenn Sie mir sagen, was @bradfitz benötigt.
Schritt 1 ist das Debuggen, warum es langsamer wurde. Wenn Sie Hinweise finden, lassen Sie es mich wissen.
@OneOfOne Wie funktioniert das für Anwendungen außerhalb der Welt? Sehen Sie dort irgendwelche Probleme? Vielleicht sind 20% für Hello World-Apps bis 1.9 akzeptabel?
@bradfitz Ich denke, die Funktion für Shutdown
führt zu einer geringeren Leistung für die Art von "Hallo Welt" -Apps / -Tests.
select {
case <-srv.getDoneChan():
return ErrServerClosed
//....
Schau hier .
Bei 1,7 war es nur eine for
Schleife.
Kann jemand meine Annahme bestätigen?
Vielen Dank,
Kataras
Ich kann die Ergebnisse des OP nicht reproduzieren. Ich bin auf einem Mac und verwende leicht ältere Versionen von 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
Es gibt einen kleinen Unterschied, aber er ist kleiner als 20%, hier fast vernachlässigbar.
@ Kataras , hast du Beweise für diese Theorie?
Sie können es selbst bestätigen: Löschen Sie diese Zeilen und messen Sie erneut.
Ich wäre jedoch überrascht.
@kataras Das sieht so aus, als ob es wahrscheinlich so ist. Zusätzlich zur Auswahl haben Sie einen Mutex-Erwerb und eine Freischaltung, die in einem Aufschub durchgeführt wird (von dem ich weiß, dass er kürzlich beschleunigt wurde, aber immer noch etwas langsamer als eine direkte Freischaltung ist).
func (s *Server) getDoneChan() <-chan struct{} {
s.mu.Lock()
defer s.mu.Unlock()
return s.getDoneChanLocked()
}
Da die Akzeptanzschleife ein so heißer Pfad ist, kann es sinnvoll sein, die Abschaltauswahl in eine separate Goroutine zu verschieben und mit sync / atomar das Herunterfahren in der Akzeptanzschleife zu signalisieren.
BEARBEITEN:
Ich denke nicht, dass es nur das ist, nur versuchtes Trinkgeld ohne die Auswahl alle zusammen und es fügt ungefähr 7us (5% ~) hinzu.
Ich verstehe, dass dies für 1.8 zu spät ist, aber warum sollte dies nicht in einer zukünftigen Version 1.8.1 behoben werden?
Hat noch jemand diese Ergebnisse reproduzieren können?
-11,2% auf Debian 8, amd64 (1.7.5 und 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 Die Implementierung ist korrekt, was bedeutet, dass der Autor vorsichtig war. Es ist nicht so
Das heißt, ich habe mich sowieso geirrt, ich habe gerade noch einmal nachgesehen und festgestellt, dass die Auswahl nur dann erfolgt, wenn beim Akzeptieren ein Fehler auftritt. Seltsam ist, wie es mein Programm konsequent verlangsamt, wenn ich es aus dem Akzeptieren entferne. Vielleicht disqualifiziert es diesen Block von einigen Optimierungsdurchläufen oder Inlining? Es kann irgendwo ein Problem geben, das eine Verlangsamung verursacht, aber es ist woanders und erfordert ein anderes Setup als meins.
@bradfitz Dies halbiert kurz und scheint zu begehen, dass faf882d1d427e8c8a9a1be00d8ddcab81d1e848e zumindest einen Teil davon verursacht. Ich sehe einen Performance-Hit von ungefähr 10% bei dieser Benchmark mit diesem Commit im Vergleich zu dem Commit davor.
@codido , danke für die Halbierung! Ja, und das ist das Commit, das ich auch vermuten würde. Gut, Bestätigung zu sehen. Das war eine der größten architektonischen Änderungen im Netz / http.Server seit geraumer Zeit.
Nach dieser Änderung habe ich kein Benchmarking (oder Optimierungen) mehr durchgeführt.
Wir können es für Go 1.9 untersuchen.
Hallo @bradfitz
Nur eine kurze Frage von einem Außenstehenden. Bitte nehmen Sie Kontakt mit mir auf, wenn ich etwas Offensichtliches verpasst habe.
Warum sollte es zu spät sein, dieses Problem zu beheben? Ist das nicht der ganze Grund für Release-Kandidaten? Um endgültige Hauptprobleme zu finden, bevor die nächste Hauptversion veröffentlicht wird?
Wenn nicht, erziehe mich bitte.
Vielen Dank, dass Sie an diesem Projekt gearbeitet haben. Ich kenne viele Leute, die diese Sprache und die Gemeinschaft um sie herum lieben. 🎉
Warum reagieren die Leute und stimmen ab, als ob dies ein großes Problem ist? Diese Änderung scheint einen Worst-Case-Performance-Effekt von ~ 40us pro Anforderung zu haben. Das klingt für mich sehr leise. Gibt es ein reales Szenario, in dem dies von Bedeutung wäre?
(bearbeiten: Ich habe mich geirrt, es ist ~ 0,5us pro Anfrage, also noch niedriger)
Ich denke, es muss möglicherweise mehr Benchmarks geben, um die Auswirkungen auf andere Dinge als die Hallo-Welt zu sehen. Dinge wie Hallo Welt üben einen hohen Benchmark-Druck auf die Interna aus und können als solche die Auswirkungen von Verlangsamungen verstärken. In einer realen Anwendung wird mehr Code für das Laden von Booten ausgeführt, wodurch der Effekt solcher Dinge theoretisch pro Anforderung weitaus geringer wird - dh er wird pro Anfrage weniger als%, was bedeutet, dass der Effekt verringert wird.
Nur meine 2 Cent.
(Ich werde mir das später genauer ansehen, wenn ich Zeit habe.)
@reimertz Ich erinnere mich, dass ich hier über den Veröffentlichungszyklus https://github.com/golang/go/wiki/Go-Release-Cycle
Sobald ein Release-Kandidat ausgestellt wurde, sollten nur Dokumentationsänderungen und Änderungen zur Behebung kritischer Fehler vorgenommen werden. Im Allgemeinen ist die Leiste für Fehlerkorrekturen zu diesem Zeitpunkt sogar etwas höher als die Leiste für Fehlerkorrekturen in einer Nebenversion. Wir ziehen es möglicherweise vor, eine Version mit einem bekannten, aber sehr seltenen Absturz herauszugeben, als eine Version mit einem neuen, aber nicht produktionstesteten Fix herauszugeben.
Eines der Kriterien für die Ausgabe eines Release-Kandidaten ist, dass Google diese Version des Codes standardmäßig für neue Produktions-Builds verwendet: Wenn wir bei Google nicht bereit sind, ihn für die Produktion auszuführen, sollten wir andere nicht dazu auffordern.
@kmlx danke für den Link! Ich war nur hier: https://golang.org/doc/contribute.html und suchte nach 'release' und konnte nichts finden. Mein Fehler.
Auch wow! Wenn Google diese Version auf seinen Produktionsservern ausführt und mit einer Auswirkung auf die Leistung im schlimmsten Fall von ~ 40 us pro Anfrage (unter Angabe von @tinco )
Aus diesem Grund bitten wir die Leute, Beta-Versionen zu testen. Wenn sie glauben, ein Problem gefunden zu haben, können sie sich frühzeitig beschweren.
go1.8beta1 wurde am 1. Dezember 2016 vor mehr als 2 Monaten veröffentlicht:
https://groups.google.com/d/topic/golang-nuts/QYuo0fai6YE/discussion
Zitat der Ankündigung:
Es ist wichtig, dass wir Fehler finden, bevor wir einen Release-Kandidaten herausgeben.
Der Release Candidate ist für die erste Januarwoche geplant.
Ihre Hilfe beim Testen dieser Beta ist von unschätzbarem Wert.
Entschuldigung, ich habe die Zahlen falsch angeschaut. Nach dem Test von go tip
in 30 Sekunden 5110713 Anfragen gestellt, das sind 5,87 us pro Anfrage. Go 1.7.5 hat 5631803 Anfragen in 30 Sekunden ausgeführt, 5.33us pro Anfrage. Wenn Sie diese also miteinander vergleichen, bedeutet dies einen Leistungsabfall von 11%. Wenn Sie es jedoch aus einer absoluten Perspektive betrachten, ist dies ein Leistungseinbruch von nur einer halben Mikrosekunde pro Anforderung. Ich kann mir nicht einmal einen HTTP-Dienst vorstellen, bei dem dies relevant wäre.
@tinco Ich stimme zu, es ist eine sehr kleine Regression, wenn man sie relativiert. Es ist jedoch immer noch sehr wichtig herauszufinden, warum es zurückgegangen ist. Es sei denn, Sie möchten eine Situation wie: # 6853 und Go 1.9 kommen mit einem weiteren Rückgang von 11%.
Davon abgesehen bin ich mir nicht sicher, warum dies mit einer Patch-Version (im Vergleich zu einer Nebenversion) nicht behoben werden konnte.
@tinco , wie viele Kerne hat dieser Computer? Multiplizieren Sie 0,5us mit der Anzahl der Kerne.
Am Mittwoch, 8. Februar 2017, um 16:13 Uhr, Sokolov Yura [email protected]
schrieb:
Wie viele Kerne hat dieser Computer? Multiplizieren Sie 0,5us mit der Anzahl der Kerne.
Warum hat die Anzahl der Kerne damit zu tun?
Jede Anforderung wird nur von einem einzelnen Kern verarbeitet.
@minux Die 5 Millionen Anfragen werden in 30 Sekunden von N Kernen bearbeitet. Die pro Anforderung für jeden Kern aufgewendete Echtzeit beträgt also 30 / 5M * N. N ist wahrscheinlich eher klein, weniger als 10 wahrscheinlich, daher ist es nicht wirklich relevant.
Kleinere Releases sind für kritische, unvermeidbare Fehler vorgesehen. Ihr Programm hat eine Wahrscheinlichkeit von 1%, dass es nach einem Tag der Ausführung zufällig abstürzt. Dies ist die Art von Fehler, die wir in einer Punktveröffentlichung beheben, mit der einfachsten, sichersten und trivialsten Korrektur, die möglich ist. Kleinere Releases dienen nicht dazu, "Ihr Programm läuft 0,5us langsamer, um einen Vorgang auszuführen, der wahrscheinlich ohnehin viel länger dauert".
Ich denke, Sie beziehen sich auf Patch-Releases ( 1.8.x
) vs Minor ( 1.x.0
).
IMO ging es bei Patch-Releases darum, Regressionen zu beheben, ohne die Funktionen oder das Verhalten zu ändern. Während dieses nicht wie ein großes aussieht, sehe ich keinen Grund, es nicht in einem 1.8.patch
zu reparieren.
Im Go-Projekt bezeichnen wir 1.x als Hauptversion und 1.xy als Nebenversion (oder manchmal als Punktversion): Go 1.8 ist eine Hauptversion; Go 1.8.2 ist eine Neben- oder Punktversion. Es macht für uns keinen Sinn, Go 1.8 als Nebenversion zu bezeichnen.
Die Freigaberichtlinie für das Go-Projekt ist unter https://golang.org/doc/devel/release.html#policy dokumentiert:
Jede wichtige Go-Version veraltet und beendet die Unterstützung für die vorherige. Wenn beispielsweise Go 1.5 veröffentlicht wurde, handelt es sich um die aktuelle Version, und Go 1.4 und frühere Versionen werden nicht mehr unterstützt. Wir beheben kritische Probleme in der aktuellen Version nach Bedarf, indem wir kleinere Revisionen herausgeben (z. B. Go 1.5.1, Go 1.5.2 usw.).
Go 1.5 ist mit einigen Einschränkungen abwärtskompatibel mit Go 1.4: Ihr Code muss nicht von undokumentiertem Verhalten abhängen (z. B. der Reihenfolge gleicher Elemente, die durch sort.Sort ausgewählt werden). Ihr Code muss verschlüsselte Strukturliterale verwenden, damit dies nicht der Fall ist brechen, wenn neue Strukturfelder hinzugefügt werden, und so weiter .
Go 1.5.1 ist so weit wie möglich abwärtskompatibel mit Go 1.5 ohne solche Einschränkungen: Wir möchten von Go 1.5 auf Go 1.5.1 aktualisieren, um einen garantiert sicheren Betrieb zu gewährleisten, ein Nicht-Ereignis, wie Sie sagen. " ohne Funktionen oder Verhalten zu ändern ".
Das Akzeptieren, dass Fehler ein unvermeidlicher Bestandteil des Schreibens von Software sind und dass jedes Mal, wenn Sie eine Änderung vornehmen, das Risiko besteht, dass ein Fehler auftritt, der nicht durch Tests vor der Veröffentlichung erkannt wird. Der beste Weg, dieses Risiko zu verringern, besteht darin, ihn nicht zuzulassen unkritische Änderungen in Punktfreigaben.
Das Beheben einer Verlangsamung um 0,5 us, die nur in Mikrobenchmarks angezeigt wird, ist eine unkritische Änderung.
@tinco Wenn wir dieses "sogenannte kleinere" Leistungsproblem nicht berücksichtigen und jedes Mal, wenn wir es ignorieren, werden wir letztendlich "langsamer". IMO will niemand, dass das passiert.
@ rashidul0405 Dieses Problem ist noch offen; niemand ignoriert es. Ich habe erklärt, warum es keine schnelle Korrektur in Go 1.8 oder Go 1.8.1 verdient.
Ich würde gerne einen 1% langsameren Go anstelle eines 1% Crashier Go nehmen.
Lassen Sie uns die Diskussion über Mailinglisten und Twitter usw. fortsetzen.
Bitte kommentieren Sie hier nur, wenn Sie an diesem Problem arbeiten.
Da anscheinend niemand daran arbeiten möchte, werde ich es schließen. Wir können nicht jedes mögliche Leistungsdetail aufspüren, und dieses wird alt.
Hilfreichster Kommentar
Hallo @bradfitz
Nur eine kurze Frage von einem Außenstehenden. Bitte nehmen Sie Kontakt mit mir auf, wenn ich etwas Offensichtliches verpasst habe.
Warum sollte es zu spät sein, dieses Problem zu beheben? Ist das nicht der ganze Grund für Release-Kandidaten? Um endgültige Hauptprobleme zu finden, bevor die nächste Hauptversion veröffentlicht wird?
Wenn nicht, erziehe mich bitte.
Vielen Dank, dass Sie an diesem Projekt gearbeitet haben. Ich kenne viele Leute, die diese Sprache und die Gemeinschaft um sie herum lieben. 🎉