Gibt es einen Unterschied zwischen blockierendem und nicht blockierendem Senden?

8

Wenn die Anwendung sicherstellen kann, dass immer Platz im Sendepuffer des Sockets vorhanden ist, würde blockierendes und nicht blockierendes Senden dieselbe Leistung haben? Gibt es in diesem Szenario irgendwelche Vorteile gegenüber dem anderen?

    
Jimm 04.12.2012, 17:49
quelle

3 Antworten

5

Der einzige Unterschied zwischen blockierendem und nicht blockierendem send besteht darin, ob der Kernel den Prozess in den Ruhezustand versetzt oder EWOULDBLOCK zurückgibt. In Bezug auf die Leistung sollte es also keinen Unterschied geben.

Ich bezweifle jedoch Ihre implizite Annahme, dass das Senden nicht blockieren kann, nur weil der Sendepuffer freien Speicherplatz hat. Stellen Sie sich einen freien Socket auf einem System vor, das hohe Anforderungen an den Arbeitsspeicher stellt. Ich würde nicht unbedingt erwarten, dass der Kernel die physikalischen Seiten für den Sendepuffer "anhefte". Ich würde erwarten, dass sie diese Erinnerung für etwas Nützliches nutzt. Und dann, wenn Sie versuchen zu senden, muss der Kernel eine freie Seite für den Sendepuffer nehmen; und wenn keine solchen Seiten verfügbar sind, könnte es sich entscheiden, EWOULDBLOCK zurückzugeben, anstatt auf (sagen wir) Swap zu warten.

Nun, das sind eine Menge "Mayben" und "Mächte", und jemand, der mit den Interna des Kernels vertrauter ist, könnte mir sagen, dass ich falsch liege. Aber selbst wenn Linux sich heute nicht so verhält, könnte es morgen sein; Und bist du 100% sicher, dass du deine Anwendung niemals auf etwas anderem als Linux ausführen wirst?

Also würde ich meine Bewerbung nicht mit solch einer fragilen Annahme schreiben. Ich schlage vor, dass Sie entscheiden, ob blockierende oder nicht blockierende Semantiken für Ihren eigenen Code sinnvoller sind und versuchen Sie nicht, die Interna des Kernels zu spielen.

[Aktualisieren]

Ich hatte gehofft, dass ich mich nicht auf die Linux-Interna einlassen müsste, aber ein übermütiger Downvoter hat mich dazu getrieben.

Beginnen Sie mit net / ipv4 / tcp.c unter dem Label "new_segment" :

%Vor%

Sehen Sie, wie sich "wait_for_sndbuf" von "wait_for_memory" unterscheidet? Darüber spreche ich.

Beim Label "wait_for_memory" erfolgt ein Aufruf an sk_stream_wait_memory mit einem Wert für timeo , der davon abhängt, ob es sich um einen nicht blockierenden Sendevorgang handelt. Diese Funktion versetzt den Prozess entweder in den Ruhezustand oder gibt EAGAIN abhängig von timeo zurück.

[Update 2]

Nur um klar zu sein, welche Frage ich beantworte ...

Ich interpretiere diese Frage so: "Wenn ich weiß, dass der Sendepuffer meines Sockets über genügend freien Speicherplatz verfügt, gibt es einen Unterschied - Leistung oder sonstwie - zwischen einem blockierenden und einem nicht blockierenden send an diesem Socket? "

Die Voraussetzung ist sicherlich möglich, wenn Ihr Protokoll beispielsweise eine Nachricht senden soll und dann erst eine neue Nachricht senden soll, nachdem eine Antwort auf eine vorherige Nachricht empfangen wurde. In diesem Fall wissen Sie, dass der Sendepuffer immer leer ist, wenn Sie send haben. Indem Sie die POSIX-Standardoption SO_SNDBUF socket abrufen und / oder setzen, können Sie wissen, dass Ihr Socket über ausreichend freien Speicherplatz verfügt. Kann sich in diesem Fall ein blockierendes send anders verhalten als ein nicht blockierendes send ?

Mein Lesen der POSIX-Spezifikation sagt grundsätzlich "ja". Mein Lesen des Linux-Quellcodes sagt "Ja" in der Praxis. Ich könnte sicherlich falsch liegen, aber es würde jemanden brauchen, der mehr über POSIX oder Linux weiß, um es zu demonstrieren, und keiner von ihnen hat diese Frage bisher beantwortet.

[Final (?) update]

Hier ist, was ich glaube POSIX erlaubt / erfordert Sie zu übernehmen.

Wenn im Sendepuffer ausreichend freier Speicherplatz vorhanden ist, kann eine blockierende send nicht für immer blockieren. Dies ist der gleiche Sinn, in dem ein Aufruf von calloc mit ausreichend freiem virtuellem Speicher nicht für immer blockieren kann. Schließlich wird das System die Ressourcen finden, die es benötigt, um Ihre Daten zu senden.

(Beachten Sie, dass das Gleiche nicht der Fall ist, wenn der Sendepuffer voll ist; in diesem Fall blockiert eine blockierende send möglicherweise für immer, je nachdem, was am empfangenden Ende des Sockets passiert.)

Auch wenn im Sendepuffer ausreichend Speicherplatz vorhanden ist, kann ein nicht blockierendes send dennoch EWOULDBLOCK zurückgeben. Wenn Sie also nicht blockierende Sockets verwenden, muss Ihr Code damit umgehen, unabhängig davon, was Sie über den Sendepuffer oder etwas anderes wissen.

    
Nemo 04.12.2012, 18:10
quelle
-1

Denken Sie daran, dass Sie nicht immer sicher sein können, dass Ihr Sendevorgang schnell ausgeführt wird.

Wenn zum Beispiel der Socket auf der anderen Seite nicht mit recv gelesen wird, ist Ihr Puffer voll.

Natürlich, wenn Sie beide Seiten der Anwendung schreiben und immer lesen, gibt es keinen signifikanten Unterschied bezüglich der Leistung, denke ich.

    
Intrepidd 04.12.2012 17:56
quelle
-1

Sie können nur sicherstellen, dass im Socket-Sendepuffer immer Platz ist, indem Sie nicht senden, wenn sie voll ist.

Sie können tatsächlich feststellen, ob im Sendepuffer Platz ist - auf einigen Systemen. Wenn im Blockiermodus kein Platz ist, können Sie () für die Schreibbarkeit auswählen - auf einigen Systemen. Auf anderen Systemen können Sie nicht feststellen, ob Platz vorhanden ist und / oder Sie können im Sperrmodus nicht wählen ().

Auf solchen Systemen haben Sie keine guten Implementierungsoptionen außer dem Senden und Blockieren oder dem Blockierungsmodus.

Auf den Systemen, auf denen Sie wissen, aber nicht auswählen können (), können Sie Schleifen und Sleeping durchführen, aber Sie können nicht wissen, wie lange Sie schlafen müssen, damit Sie zu lange schlafen und Zeit verschwenden, im Gegensatz zum Blockieren blockieren für genau die richtige Länge der Zeit.

    
EJP 04.12.2012 20:09
quelle

Tags und Links