Laden...

Stream auslesen dauert sehr lange - schnellerer Weg?

Erstellt von mosspower vor 14 Jahren Letzter Beitrag vor 14 Jahren 5.067 Views
mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren
Stream auslesen dauert sehr lange - schnellerer Weg?

Hallo "Kollegen",

in dem Stream befinden sich "lediglich" 300 KB. Warum dauert das so lange?
Gibt es einen anderen, effizienteren Weg?

Hier der Quellcode:


private static byte[] ReadStream(Stream stream) {
      byte[] buffer = new byte[50000];
      byte[] streamContent = null;
      int readChars = int.MinValue;

      MemoryStream memoryStream = new MemoryStream();

      while(true) {
        DateTime starta = DateTime.Now;
        // !!! Hier dauert es ewig !!!
        readChars = stream.Read(buffer, 0, buffer.Length);
        // !!! End ewig !!!
        DateTime startb = DateTime.Now;

        if(readChars > 0) {
          memoryStream.Write(buffer, 0, readChars);
        }
        else {
          break;
        }
      }

      streamContent = memoryStream.ToArray();
      memoryStream.Close();
      stream.Close();

      return streamContent;
    }


Ich habe die Stelle gekennzeichnet - hier dauert es sehr lange (ca. 7 Sekunden). Ist das "normal" bei nur 300 KB?

Gruß und danke schon einmal für etwaige Antworten.

3.170 Beiträge seit 2006
vor 14 Jahren

Hallo,

7 Sekunden kommt mir schon recht lange vor... um was für eine Art Stream handelt es sich denn da (Network, File, Memory)?

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

Gelöschter Account
vor 14 Jahren

könnte es sein ,das evtl im stream keine 50000 byte drinn sind und das er deswegen blockiert, da er noch nicht genug daten zum lesen hat?

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

Hallo MarsStein,

es handelt sich um einen Response-Stream von einem HttpWebResponse-Objekt.
Zuerst dachte ich, dass eben die Leitung zu langsam ist (was hier durchaus sein kann), jedoch dauert der Aufruf nicht so lange, sondern das lesen.

Ich denke, wenn die GetResponse abgeschlossen ist, dann ist das "Zeugs" im Stream auf dem Server, bzw. da wo eben das Programm läuft - und dann dauert eben das Lesen so lange.

Die Zeilen für den Aufruf ....


HttpWebResponse webResponse = null;

        try {
          webResponse = (HttpWebResponse)webRequest.GetResponse() ...


dauern nicht so lange, eben nur das Lesen aus dem Stream danach.

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

könnte es sein ,das evtl im stream keine 50000 byte drinn sind und das er deswegen blockiert, da er noch nicht genug daten zum lesen hat?

Hallo JAck30lena,

nein, das habe ich gleich zu Beginn getestet - das fällt aus, denn er geht ein paar mal in den If-Zweig.

Gruß

2.921 Beiträge seit 2005
vor 14 Jahren

@mosspower: Ich hatte einmal die gleiche Erfahrung gemacht.
Ich weiß aber nicht mehr was das bei HTTPRequest war. Man muss noch irgendwelche Properties setzen sonst ist es so langsam beim ersten mal.

Alternative:

Webseiten auslesen mit HttpWebRequest

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

3.971 Beiträge seit 2006
vor 14 Jahren

probier mal


byte[] data = null;
using (StreamReader reader = new StreamReader(stream)) {
  data = reader.ReadToEnd();
}

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

@dr4gOn76,

das Problem scheint bekannt zu sein, jedoch habe ich hierfür keine Lösung gefunden.

Klick!

Hier wird vorgeschlagen, das Proxy-Objekt auf null zu setzen - ich kann jetzt nicht sagen, dass es schneller geht.

Der hängt bei mir von 3 - 8 Sekunden drinnen. (für 4 PDF-Dokumente + Soap-Envelope mit nur ca. 300 KB 😛)

Kann mich mal einer aufklären, wie das technisch abläuft? Ich dachte immer, nachdem ich den Response geholt habe, dass die Verbindung dann abgeschlossen ist und ich "nur noch" den Stream auslesen muss oder hängt das Auslesen des Streams noch irgendwie mit dem Endpoint zusammen?

Denn wie gesagt, ich habe hier eine langsame Leitung 2MB, aber der Aufruf ist es nicht, der solange dauert, sondern das Auslesen.

Auch der Vorschlag von kleines Eichhörnchen hat leider nichtst gebracht - trotzdem danke für den Vorschlag.

Mir fällt gerade auf, dass ich bei Sokets mit FTP das auch schon erlebt habe, dass das auslesen ewig dauert - kann ggf. an .NET liegen, denn mit z.B. FileZilla (C++-Programmierung) geht das ratz-fatz! - ist aber jetzt andere Baustelle.

3.971 Beiträge seit 2006
vor 14 Jahren

Bei Socketprogrammierung gibts die Socket.Available-Eigenschaft , die die Anzahl der empfangenen Bytes zurückgibt, die zum Lesen (Socket.Recieve) bereitstehen.

Verwendet man immer den kleinsten Wert aus verfügbar und Buffer-Größe blockiert Recieve am Ende nicht.

Leider ist NetworkStream.DataAvailable ein Boolean.

Man könnte aber per Reflection herankommen und die verfügbaren Bytes mit Networkstream.m_StreamSocket.Available abfragen

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Gelöschter Account
vor 14 Jahren

könnte es sein ,das evtl im stream keine 50000 byte drinn sind und das er deswegen blockiert, da er noch nicht genug daten zum lesen hat?
Hallo JAck30lena,

nein, das habe ich gleich zu Beginn getestet - das fällt aus, denn er geht ein paar mal in den If-Zweig.

Gruß

ich habe zur sicherheit noch ein wenig recherchiert und es läuft immer darauf hinaus, das man mehr lesen möchte, als überhaupt da ist. löst man das problem, löst man auch sein performance problem.

2.921 Beiträge seit 2005
vor 14 Jahren

@Jack30Lena:

Ich denke IMHO dass mosspower nicht weiß, wie Du recherchiert hast, wäre bestimmt interessant für die User hier zu posten.

😃

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Gelöschter Account
vor 14 Jahren

sowas poste ich eigendlich immer aber nun war das ganze nicht eindeutig abzugrenzen. es waren jede menge blogs und forum-threads im netz, wo ich mir die problemstellung angesehen habe und bei vergleichbarem problem dann gelesen habe.... nicht immer war eine lösung dabei (eigendlich nur selten) aber oft wurde das problem genau in dem missverhältniss von auslesegröße und vorhandenen daten identifiziert.

in spezifischen fällen wurde vorgeschlagen, das man sich ein protokoll ausdenkt, das die zu lesende größe in einem header mitgibt und dann beim auslesen zuerst der header gelesen wird und dann ein buffer mit der länge initialisiert wird.....

allerdings ist das in diesem falle glaube ich nciht möglich?
evtl kannst du aber im header nachschauen ob etwas mit contentlength drinn steht. dann musst du nur noch den kompletten header + content length auslesen. das dürfte so funktionieren?

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

Leider habe ich die Contentlänge nicht, die steht immer, komischerweise, auf -1.
Das mit dem mehr Auslesen als vorhanden ist, kann ich nicht bestätigen, da es auch beim chunkweisen Auslesen immer wieder Wartezeiten gibt, also wenn weniger ausgelesen wird in der obigen Schleife.

Ich nehme einmal an, dass es die Leitung ist, denn heute sind mir erstmalig zwei Extremwerte aufgefallen.

Eine Zeit lang dauerte es lediglich 800 Millisekunden, dann auch schon mal 36 Sekunden - da macht definitiv jemand die Leitung dicht.

Ich gehe mal schwer davon aus, dass es programmiertechnisch richtig implementiert ist - den Rest sollen die selber auskasperln.

Ich danke euch für eure Hilfe.

P.S. Kann mir jemand sagen, wie das technisch nach dem Anfordern des Responses, mit GetResponse, weiterläuft? Wo befindet sich der Stream? Auf meinem Rechner oder irdendswo auf dem Server, mit dem man ins Netz geht? Komisch ist nämlich, dass nämlich das das Lesen öfters länger dauert als der Aufruf. Bin ich da noch irgendwie mit dem Endpoint "verdrahtet", also dass ich beim Lesen von dort noch was hole? Das sollte doch schon abgeschlossen sein, wenn ich den ResponseStream habe. Naja, eigentlich sollte es doch genauso schnell gehen, wie wenn ich aus einem File lese, was ja auch, siehe 800 Milllisekunden, manchmal geht.

Gelöschter Account
vor 14 Jahren

dafür musst du eine schicht weiter runter ins TCP protokoll. wenn du eine 2 GB datei hast, dann versendest du sie ja auch nciht in einem stück, sondern in kleinen häppchen. sobald das erste häppchen ankommt, kannst du dir ja schon den stream holen und der rest wird dann einfach in den stream geschoben....

der stream ist also eine art recive-parkplatz und dürfte sich glaube ich im ram befinden... allerdings bin ich mir beim letzteren nciht sicher.

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

OK, das bedeutet, wenn ich den Response abgeholt habe, dann ist lediglich der Request auf dem Server abgeschlossen? Die Antwort des Servers muss ich mir dann mittels des Auslesens des Streams holen. Würde ich das nicht machen, dann bleibt das ganze "Zeugs" noch auf dem Server rumliegen - eben bis zum eingestellten Timeout?

Wow, wenn das so ist, denn das habe ich nicht gewusst.

Hier noch mal ein paar Debugmeldungen. Es dauert oft 0 Millisekunden und dann wieder länger - Es liegt definitiv nicht an den Chunks, bzw. der Größe von diesen.

Start

Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.2656284 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.5781324 Read 50000 bytes - took 00:00:00.1406268 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.3437544 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.2343780 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1875024 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1406268 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1875024 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0156252 Read 50000 bytes - took 00:00:00.1718772 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0468756 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1250016 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0937512 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1718772 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0156252 Read 50000 bytes - took 00:00:00.2343780 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.2656284 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1562520 Read 50000 bytes - took 00:00:00.6718836 Read 50000 bytes - took 00:00:00.7187592 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.2343780 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00.1718772 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00.0156252 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0937512 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1406268 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0937512 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0937512 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1718772 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1718772 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00.1093764 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00.0781260 Read 50000 bytes - took 00:00:00 Read 50000 bytes - took 00:00:00

Duration total 00:00:07.3125936

Gelöschter Account
vor 14 Jahren

ist das das auslesen eines einzigen response?

wie hast du genau gemessen?

mosspower Themenstarter:in
456 Beiträge seit 2007
vor 14 Jahren

Ja, ist ein einziger Response.

Zeit gestoppt einfach so ....


DateTime readStart = DateTime.Now;
readChars = stream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Read 50000 bytes - took " + DateUtil.GetTimeSpanForNow(readStart));

Gelöschter Account
vor 14 Jahren

mach das mal lieber mit dem StopWatch 😉

3.971 Beiträge seit 2006
vor 14 Jahren

Du musst weiterhin zwischen TCP und UDP unterscheiden. Bei Dateiübertragungen wird TCP verwendet, wo der Empfänger bestätigen muss was er an Daten erhalten hat (Checksumme).

Bei UDP (beispiel Videoübertragung) ist dem Sender ziemlich egal, ob was auf dem Weg verloren geht.

@Mosspower
hattest du mal die Idee mit Socket.Available getestet? Wenn nicht, hätte ich für dich hier einen kleinen fertigen Wrapper zum porbieren.


class NetworkStreamWrapper : Stream {


	private NetworkStream m_stream;
	private Socket m_socket;

	public NetworkStreamWrapper(NetworkStream stream) {
		if (stream == null) throw new ArgumentNullException("stream");
		m_stream = stream;
	}

	private void GetSocket() {
		m_socket = (Socket)(typeof(NetworkStream).GetField("m_StreamSocket", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(m_stream));
	}

	public override int Read(byte[] buffer, int offset, int count) {
		if (m_socket == null) GetSocket();

		return m_stream.Read(buffer, offset, Math.Min(count, m_socket.Available));
	}

	public override bool CanRead {
		get { return m_stream.CanRead; }
	}

	public override bool CanSeek {
		get { return m_stream.CanSeek; }
	}

	public override bool CanWrite {
		get { return m_stream.CanWrite; }
	}

	public override void Flush() {
		m_stream.Flush();
	}

	public override long Length {
		get { return m_stream.Length; }
	}

	public override long Position {
		get {
			return m_stream.Position;
		}
		set {
			m_stream.Position = value;
		}
	}

	public override long Seek(long offset, SeekOrigin origin) {
		return m_stream.Seek(offset, origin);
	}

	public override void SetLength(long value) {
		m_stream.SetLength(value);
	}

	public override void Write(byte[] buffer, int offset, int count) {
		m_stream.Write(buffer, offset, count);
	}
}

Hab im Moment leider nicht so viel Zeit zum testen.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

L
667 Beiträge seit 2004
vor 14 Jahren

Das ganze Problem lässt sich maximal simpel umgehen, indem man in den Stream immer über einen StreamWriter mit WriteLine() und entsprechend aus dem Stream mit einem StreamReader mit ReadLine() ausliest.

Dadurch kann es dir schnuppe sein, wie lange die Message ist. Gut, in Deinem Fall ist der Sender ein Webprojekt, vielleicht ist es da ja möglich die WebResponse abzufangen und dann selbst in den Stream zu schreiben ? Kenne mich mit der Webentwicklung unter .NET aber nicht so wirklich aus...

"It is not wise to be wise" - Sun Tzu

L
53 Beiträge seit 2007
vor 14 Jahren

Ich würde auf Internet Explorer -> Verbindungseinstellungen -> Automatische Suche nach Einstellungen tippen.
Wenn das eingeschaltet ist (Standard) versuchen auch die .NET-Klassen beim ersten Request die Proxy-Einstellungen automatisch zu suchen. Was darauf hinausläuft, dass ein bestimmter DNS-Namen ausgelesen wird, der in den meisten Netzen nicht vorhanden ist. Das erzeugt ein Timeout von ein paar Sekunden.

32 Beiträge seit 2010
vor 14 Jahren

Ich würde mal ganz konkret sagen, du öffnest einen Wireshark, filterst die Pakete, die auf dich bzw. deinen Remote-Host zutreffen und siehst dir mal an, ob, falls das ganze länger dauert, bis zum Ende Daten übertragen werden, oder ob die Datenübertragung schon vorher abgeschlossen ist.

Ich denke, das sollte dir wirklich Aufschluss darüber geben, ob das ganze nun an der .NET Api oder irgendeinem Problem auf Programmebene oder am Netzwerk liegt.

#define struct union[