Mehrere TCP/IP Verbindungen
-
volkard schrieb:
Pro Anfrage einmal Threadstart und -end, und kalte Sprungvorhersagetabellen? Macht großzügig aufgerundet hundert Mikrosekündchen? Aber die Webseite nudelt ein Script durch mod-reqrite, PHP und mySQK, und zahlt dafür 30ms.
100 µs sind schon einmal die richtige Größenordnung. Invertiert sind das gerade einmal 10 kHz. Maximal gehen damit also 10000 Verbindungen pro Sekunde und Hardware-Thread. Das reicht sicher für 99% der Anwendungen. Wenn man aber über Performance spricht, meint man eigentlich immer die 1% der Anwendungen, bei denen tatsächlich optimiert werden muss. Bei den 1% lässt man sich dann etwas schlaueres einfallen als Threads.
Wenn man PHP benutzt, ist das sowieso alles egal. Dann kann man auch seinen Webserver in Bash mit
netcatschreiben.Beim Ausliefern von statischen Dateien wäre ein Thread pro Verbindung ein unnötiger Flaschenhals.
-
TyRoXx schrieb:
Beim Ausliefern von statischen Dateien wäre ein Thread pro Verbindung ein unnötiger Flaschenhals.
Ja.
TyRoXx schrieb:
Wenn man aber über Performance spricht, meint man eigentlich immer die 1% der Anwendungen, bei denen tatsächlich optimiert werden muss. Bei den 1% lässt man sich dann etwas schlaueres einfallen als Threads.
Akso sollten Leute, die noch fragen müssen, ob sie dies oder jenes machen, zu 99% die Antwort "Ein Thread pro Client" bekommen. Das sehe ich auch so.
Sowas da http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html betrifft weniger als 1% fürchte ich beinahe.
-
volkard schrieb:
Sowas da http://highscalability.com/blog/2013/5/13/the-secret-to-10-million-concurrent-connections-the-kernel-i.html betrifft weniger als 1% fürchte ich beinahe.
Und wenn es einen betrifft will man eh einen custom Treiber verwenden.

The kernel isn’t the solution. The kernel is the problem.
Besser hätte ich es nicht schreiben können.
-
Das eigentliche Hauptargument gegen Thread-per-Connection ist/war, dass es zwar skalierbar sein kann, es aber Systeme gibt/gab, wo der Scheduler eben nicht mit O(1) läuft, sodass diese Lösung nicht skalierbar UND plattformunabhängig war/ist.
Der Artikel ist ganz nett, sieht aber wie ein Horror-Szenario/Wunschdenken aus. Relativ betrachtet werden vielleicht 1% der Leute sich mit Millionen Verbindungen beschäftigen müssen, aber die absolute Zahl wird bestimmt ansteigen. Die sollen dann alle ihre eigenen Kernel-Mode-Treiber schreiben (á la Microsoft IIS' HTTP-Treiber) und lock-freie Algorithmen benutzen: allesamt extrem hoch spezialisierte Einzelbereiche. Kaum auszudenken, wie einem da die Bugs, ABA-Probleme, Deadlocks (und dank Treiber auch noch) Kernel-panics/Bluescreens um die Ohren fliegen werden.
-
TL;DR: Keiner von euch hat Erfahrung und ihr ratet alle rum.
-
mehr schrieb:
TL;DR: Keiner von euch hat Erfahrung und ihr ratet alle rum.
Machen das nicht alle Softwareentwickler die ganze Zeit? Erfahrung fällt nicht vom Himmel.
-
mehr schrieb:
TL;DR: Keiner von euch hat Erfahrung und ihr ratet alle rum.
Bei welchem Punkt?
Aber das alle rumraten, das glaube ich nicht.
-
Jodocus schrieb:
Die sollen dann alle ihre eigenen Kernel-Mode-Treiber schreiben (á la Microsoft IIS' HTTP-Treiber) und lock-freie Algorithmen benutzen: allesamt extrem hoch spezialisierte Einzelbereiche. Kaum auszudenken, wie einem da die Bugs, ABA-Probleme, Deadlocks (und dank Treiber auch noch) Kernel-panics/Bluescreens um die Ohren fliegen werden.
Oder sie nutzen halt Projekte wie PF_RING.

-
Oder die 99.99% der Entwickler die Software schreiben wo es vollkommen egal ist halten einfach den Rand, anstatt dass sie versuchen ihre Kollegen zu missionieren.
Ich möchte nicht wissen wie viel Geld vernichtet wurde durch schlechte Ratschläge wie "mach mal asynchron weil sonst is voll langsam". Und dann sitzt Otto-Normalprogrammierer da und programmiert sich nen Ast ab für den < 1 call/second Server. Was sonst in 10 Minuten erledigt gewesen wäre.
-
Wären 2 Threads pro Client nicht angebrachter, da TCP Sockets full duplex sind?
-
hustbaer schrieb:
Mein Vorschlag wäre pro Verbindung einen Thread zu nehmen, und dann alles mit synchronem IO zu machen.
Super einfach und wer behaupten möchte dass es von der Performance her schlecht ist, der soll es mir erstmal beweisen
Danke, da ich bisher wenig mit Threads gearbeitet habe. Kannst du es mir bitte etwas genauer erläutern?
Gruß
-
socket = socket() bind(socket) listen(socket) while(true) { new_socket = accept(socket) new_thread(new_socket); } void new_thread(socket) { recv(socket); send(socket); ... closesocket(socket); }
-
Danke für die Antwort.
Achso logich der Thread bleibt beim ersten resv hängen aber dafür wird dann der nachfolgende Thread ausgeführt.
kapiert!
-
^ Oder ?
Also wenn anschließend ein zweiter Thread kommen würde. Würde dann der erste bei resv einen blocking call erhalten und der nächste würde ausgeführt werden?
Danke Gruß
-
Der Hauptthread empfängt neue Clients und deligiert sie in neue Threads, die dann blocken/whatever machen. Er selber blockiert nur während er auf neue Clients wartet, sonst nicht. Falls doch, dann würden halt Clients nicht mehr akzeptiert werden und früher oder später abgewiesen.
-
hustbaer schrieb:
Ich möchte nicht wissen wie viel Geld vernichtet wurde durch schlechte Ratschläge wie "mach mal asynchron weil sonst is voll langsam". Und dann sitzt Otto-Normalprogrammierer da und programmiert sich nen Ast ab für den < 1 call/second Server. Was sonst in 10 Minuten erledigt gewesen wäre.
Ach, aber "Otto" kommt von selbst auf die Idee einen neuen Thread für die Verbindung zu erstellen?
"Otto" hat typischerweise auch keine Ahnung von Multi-Threading und produziert fröhlich Abstürze. Ich möchte nicht wissen, wie viel Geld seiner Kunden dadurch vernichtet wurde.
Ich halte diese Otto-Normalidiotenbeispiele für schädlicher als die guten Ratschläge. Die zementieren nur die Don't-Care-Mentalität, die ohnehin schon zu präsent ist. Wenn man von seinen Mitmenschen erwartet, dass sie sich idiotisch verhalten, werden so das auch tun.
Sinnvoller fände ich es den Otto mal grundsätzlich über Nebenläufigkeit aufzuklären. Wenn er verstanden hat, was alles möglich ist, kann er gerne einen Thread pro Client verwenden. Wenn man ihm zusäzlich erklärt hat, wie man Software-Komponenten voneinander trennt, kann er später problemlos seinen Thread-Ansatz überarbeiten, falls es mal erforderlich werden sollte.
-
Hier mal ein kleiner Echo-Server (für Linux), der pro Verbindung einen neuen Thread aufmacht:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <iostream> #include <thread> #include <vector> int main() { using namespace std; int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listen_socket < 0) { cerr << "socket() failure\n"; return -1; } sockaddr_in saddr{ }; saddr.sin_port = htons(40001); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listen_socket, reinterpret_cast<sockaddr*>(&saddr), sizeof saddr) < 0) { cerr << "bind() failure\n"; close(listen_socket); return -2; } if(listen(listen_socket, SOMAXCONN) < 0) { cerr << "listen() failure\n"; close(listen_socket); return -3; } for(;;) { sockaddr_in client_addr{ }; socklen_t addr_len = sizeof client_addr; int client_socket = accept(listen_socket, reinterpret_cast<sockaddr*>(&client_addr), &addr_len); if(client_socket < 1) { cerr << "accept() failure\n"; } else { thread([=]() { vector<char> buffer(512); int result = 0; do { result = recv(client_socket, &buffer[0], buffer.size(), 0); if(result < 0) { cerr << "recv() failure\n"; close(client_socket); return; } else if(result != 0) { if(send(client_socket, &buffer[0], result, 0) < 0) { cerr << "send() failure\n"; close(client_socket); return; } } else { close(client_socket); return; } } while(true); }).detach(); } } }Edit: Trotzdem sei dir schwer geraten, eine Library zu benutzen. Dann musst du dich auch nicht mit Plattformabhängigkeit und I/O-Strategien wie 1 Thread pro Verbindung etc. rumplagen.
-
TyRoXx schrieb:
Ach, aber "Otto" kommt von selbst auf die Idee einen neuen Thread für die Verbindung zu erstellen?
Jupp, klar.
-
Jodocus schrieb:
Edit: Trotzdem sei dir schwer geraten, eine Library zu benutzen. Dann musst du dich auch nicht mit Plattformabhängigkeit und I/O-Strategien wie 1 Thread pro Verbindung etc. rumplagen.
Jop.
Boost.Asio ist z.B. nicht grundsätzlich böse. Man muss nur "As" Teil ignorieren
-
Jodocus schrieb:
Hier mal ein kleiner Echo-Server (für Linux), der pro Verbindung einen neuen Thread aufmacht:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <iostream> #include <thread> #include <vector> int main() { using namespace std; int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listen_socket < 0) { cerr << "socket() failure\n"; return -1; } sockaddr_in saddr{ }; saddr.sin_port = htons(40001); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listen_socket, reinterpret_cast<sockaddr*>(&saddr), sizeof saddr) < 0) { cerr << "bind() failure\n"; close(listen_socket); return -2; } if(listen(listen_socket, SOMAXCONN) < 0) { cerr << "listen() failure\n"; close(listen_socket); return -3; } for(;;) { sockaddr_in client_addr{ }; socklen_t addr_len = sizeof client_addr; int client_socket = accept(listen_socket, reinterpret_cast<sockaddr*>(&client_addr), &addr_len); if(client_socket < 1) { cerr << "accept() failure\n"; } else { thread([=]() { vector<char> buffer(512); int result = 0; do { result = recv(client_socket, &buffer[0], buffer.size(), 0); if(result < 0) { cerr << "recv() failure\n"; close(client_socket); return; } else if(result != 0) { if(send(client_socket, &buffer[0], result, 0) < 0) { cerr << "send() failure\n"; close(client_socket); return; } } else { close(client_socket); return; } } while(true); }).detach(); } } }Edit: Trotzdem sei dir schwer geraten, eine Library zu benutzen. Dann musst du dich auch nicht mit Plattformabhängigkeit und I/O-Strategien wie 1 Thread pro Verbindung etc. rumplagen.
Danke für die Antwort und das Beispiel. Aber ist es hier nicht so das alle Verbindungen über den gleichen Port laufen?
Gruß