C# WebClient extrem langsam?


01.03.2022, 21:08

Übrigens, nach zusätzlichen ca. 10 Minuten warten (noch etwas mehr), mit exakt dem oben stehenden Code, sieht meine Fortschrittsleiste so aus:

Ich hätte nur gerne diese Leiste und das scheint nur per WebClient zu gehen (ein event zu haben immer wenn es Fortschritt gibt). Gäbe es schnellere Alternativen würde ich sofort wechseln.

Die Datei die ich laden will ist übrigens: http://addresses.loyce.club/Bitcoin_addresses_LATEST.txt.gz

1 Antwort

...wird Deine Anzeige vielleicht nur nicht aktualisiert?

Vielleicht solltest Du Dir die Zieldatei einfach anschauen, die Dürfte normal geladen werden.

In Zeile 33 hast Du ein "nettes" Console.ReadKey();

In einer Callbackfunktion ein totales NoGo.... . selbst ein simples WriteLine kann unter Umständen so langsam sein, das sich Events gegenseitig auf die Füße treten.

wie Zeitkritisch Callbackst sind zeigt folgende Demo

using System;
using System.Net;
using System.ComponentModel;
class Prog{

  public static void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
  {
    Console.WriteLine("completed");
  }
  
  public static void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
  {
        //ist so langsam,  das das Event ca. 3 mal gefeuert hat noch  bevor der  Corsor  wieder auf die angegebene Position springen  kann
      Console.SetCursorPosition(0,10);
      Console.WriteLine(e.ProgressPercentage);
    //Console.ReadKey();  //<--sowas ist total Kacke in einer Callbackfunktion
  }
  
  static void Main(string[] args){
    WebClient wc = new WebClient();
    wc.DownloadFileCompleted += Prog.DownloadCompleted;
    wc.DownloadProgressChanged += DownloadProgressChanged;
    wc.DownloadFileAsync(new Uri("http://addresses.loyce.club/Bitcoin_addresses_LATEST.txt.gz"), "test.bin");


    Console.WriteLine("warte  auf das Ende");
    Console.ReadKey();
  }

}


OlMi1 
Fragesteller
 02.03.2022, 14:56

TL;DR: Fortschritt wird jetzt öfter aufgerufen aber berechneter Fortschritt in Prozent ist 0, obwohl es normal und schnell runter lädt.

Du hast komplett recht.

Das entfernen vom Console.ReadLine() macht es um einiges schneller (bemerkbar daran, dass die kleine Animation neben dem Ladebalken schneller abgespielt wird, da die am aktualisieren des Fortschrittes hängt).

Leider komme ich trotzdem nicht über einen Fortschritt von einem Prozent. Habe mir die Menge an Bytes und den Download-Fortschritt jetzt mal so ausgeben lassen, dass ich den berechneten Fortschritt (bytesGeladen / gesamtBytes * 100) und die zahl der geladenen Bytes angezeigt bekomme.

Die Zahl an Bytes erhöht sich unglaublich schnell und erreicht auch recht fix die erwarteten Mengen. Das bedeutet dass der Download an sich zu funktionieren scheint. Das Reflektiert sich auch dann wenn man sich die Dateigröße des Downloads über die Dateiinformationen ausgeben lässt.

Erreicht der Download nun sein Ende, dann geht der Fortschritt ganz am Ende auf 100 (mit der Berechnung so: double percentage = bytesIn / totalBytes). Dann wird mein Download-Fortschritts-Event nicht mehr aufgerufen. Mein End-Event aber schon.

0
OlMi1 
Fragesteller
 02.03.2022, 15:03
@OlMi1

Also, ich habe jetzt vermutet dass einfach nicht die richtigen Werte ankommen. Die Ausgabe wiederlegt das aber. Hier habe ich einmal mit den Werten die mein Programm mir sagt gearbeitet und nachgerechnet: https://ibb.co/41TBvbM

0
OlMi1 
Fragesteller
 02.03.2022, 15:19
@OlMi1

auch die eingebaute Lösung e.ProgressPercentage gibt nur Müll zurück. Was kann ich da machen?

0
Erzesel  02.03.2022, 21:38
@OlMi1

Die Problematik bei Leuten wie Dir ist, das Ihr euch ein Thema herausgreift, welches über Eure Grundkenntnisse hinaus geht. Da werden irgendwelche Codeschnippsel zusammenkopiert, ohne wirklich verstanden zu haben wie die Sache funktioniert.

Es ist nahezu unmöglich hier eine Art Privatunterricht zu zelebrieren.

zum Thema Ereignisverarbeitung schau Dir folgendes an:

Sowie das übrige Texte zum ComponentModel:

0
OlMi1 
Fragesteller
 02.03.2022, 23:17
@Erzesel

Naja. Da muss man nicht gleich so kommen.

Zudem geht die Frage an einen sehr spezifischen Punkt, nämlich das Fehlschlagen einer Division. Sollte doch einfach sein, oder? Hat auch nichts mit Events zu tun, hätte man meinen Text gelesen.

Zudem weiß ich sehr wohl wie das funktioniert, danke.

0
Erzesel  03.03.2022, 08:36
@OlMi1
nämlich das Fehlschlagen einer Division. 

Ich dachte es ging um :

e.ProgressPercentage gibt nur Müll zurück
 einfach nicht die richtigen Werte ankommen...

Es scheint doch schlimmer um die Basics zu stehen...😖

Schulbildung

Prozentrechnung : BytesReceived *100/TotalBytesToReceive

C# basics:

  • IntergerVariable +-*/ Integervariable = IntegerErgebnis
  • FloatVariable +-*/ Integervariable = Ergebnis

Ich bin nicht böse oder frech, wenn ich moniere, das Anfänger mit Forms/WEP herumzaubern und nicht wissen was unter der Haube passiert...

ganz einfach mal in der console...:

using System;
class Prog{
 static void Main(string[] args){
  int a=7;
  int b=3;
  Console.WriteLine(a/b); // int / int = int
  Console.WriteLine((double)a/b); //caste einen Teil der Formel zu Double und das Ergebnis ist Double
  Console.WriteLine(a*1.0/b);   // ...ein Teil der Formel ist Double 
  Console.ReadKey();
 }
}

oder mein obiges Script verfeinern:

using System;
using System.Net;
using System.ComponentModel;
class Prog{
 public static void DownloadCompleted(object sender, AsyncCompletedEventArgs e){
  Console.WriteLine("completed");
 }
 public static void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e){
   
  Console.WriteLine("downloaded {0} of {1} bytes. {2} % complete...FixpointPercentage:{3,7:f3} %",
   e.BytesReceived,
   e.TotalBytesToReceive,
   e.ProgressPercentage,
   (e.BytesReceived*100.0/e.TotalBytesToReceive) 
  );
 }

 static void Main(string[] args){
  WebClient wc = new WebClient();
  wc.DownloadFileCompleted += DownloadCompleted;
  wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
  wc.DownloadFileAsync(new Uri("http://addresses.loyce.club/Bitcoin_addresses_LATEST.txt.gz"), "test.bin");
  Console.ReadKey();
 }
}

Ich mache die Beispiele für die Console ja nicht weil ich zu dumm für Forms bin, Sondern um alles überflüssige wegzulassen, damit der FS kapiert was unter der "Motorhaube passiert...



0
OlMi1 
Fragesteller
 03.03.2022, 18:01
@Erzesel

Nutze selbst auch die Konsole.

Es ging mir auch nicht darum, dich blöd darstehen zu lassen oder kacke zu dir zu sein.

Hier ging es mir mehr darum, zu fragen, was ProgressChangedEventArgs.ProgressPercentage anderes macht als die Division. Ein Int wird zurückgegeben, also kann es 0 für läuft und 1für fertig oder 1-100 für den Fortschritt sein. Es ist letzteres; "A percentage value indicating the asynchronous task progress.". Also der Fortschritt in Prozent - wieso dann immer 0?

Die bytesReceived und TotalBytesReceived Variablen können ausgegeben werden und sind dann richtig, aber nicht in anderen Operationen genutzt werden - mindestens eine ist immer 0. Das war meine eigentliche Frage hier.

Und wieso sollte man die erhaltenen Bytes * 100 rechnen? Sollten nicht die erwarteten und erhaltenen Bytes beide in der Einheit "Byte" und damit direkt zum rechnen nutzbar sein?

0
Erzesel  03.03.2022, 21:47
@OlMi1

Ich kann Dir nicht sagen weshalb bei der Eventhandler von DownloadFileAsync bei Dir nur 0 übergibt bei mir läuft der Download (meist) perfekt durch. ("Meist", weil es bei mir gelegentlich passierte, dass bei zu häufigem probieren der Datei, der Server den Request ablehnte?)

wieso sollte man die erhaltenen Bytes * 100 rechnen? 

Prozentrechnen ... Dreisatz ? (7.Klasse):

Prozentsatz zu Prozentwert   wie   100 zu Grundwert

...also...

Prozentsatz/Prozentwert =  100/Grundwert

...Prozentwert auf der linken Seite ausmultiplizieren...

Prozentsatz/Prozentwert *  Prozentwert = 100/Grundwert * Prozentwert

...Auf der linken Seite kürzt sich der Prozentwert weg. Es bleibt...

Prozentsatz = 100/Grundwert * Prozentwert

Da es bei einer Multiplikation pupsegal ist auf welcher Seite ein Multiplikator steht, geht eben auch:

Prozentsatz = Prozentwert * 100/Grundwert

Dem Mathelehrer ist es egal, genauso wie dem Compiler...

Sollten nicht die erwarteten und erhaltenen Bytes beide in der Einheit "Byte" und damit direkt zum rechnen nutzbar sein?

Prozentrechnen hat ersmal nix mit Einheiten zu tun. Ebenso könnte ich auch mit Bananen rechnen

Der Datentyp von e.BytesReceived und e.TotalBytesToReceive ist übrigens long (heute sind Dateien auch größer als ein uint (4.294.967.295)) .

Um den Prozentsatz mit Kommastellen zu bekommen zwinge ich durch die Double-Kostante 100.0 (statt 100) den Compiler zu einen impliziten Typecast aller Komponenten der gesamten Formel.

0
OlMi1 
Fragesteller
 05.03.2022, 15:13
@Erzesel

War bei dem * 100 nur verwirrt. Ich hätte bytesIn / bytesTotal * 100 gemacht, so wie ich es in der Schule gelernt habe.

Prozentrechnen hat ersmal nix mit Einheiten zu tun. Ebenso könnte ich auch mit Bananen rechnen

Jup, das war mir durchaus klar. War aber der Grund für meine Verwirrung von weiter oben, weil eben beide Werte die gleiche Einheit (eben Byte) haben und ich nicht erst noch was umrechnen müsste (Mb in Byte oder so wat)

Habe jetzt das hier:

double bytesIn = Convert.ToDouble((double)e.BytesReceived);
double totalBytes = Convert.ToDouble((double)e.TotalBytesToReceive);
double percentage = e.BytesReceived / e.TotalBytesToReceive;

Ergebnis ist trotzdem 0. Wobei da tatsächlich 0 und nicht 0.0 steht. (Randnotiz: Habe es einmal mit und einmal ohne den zusätzlichen cast zu double probiert, bringt beides nix.)

Ein Test mit Dummy-Longs:

percentage = Convert.ToDouble((long)1) / Convert.ToDouble((long)5);

Raus kommt 0.2 => 20%, also das richtige Ergebnis.

0
Erzesel  05.03.2022, 17:21
@OlMi1
e.BytesReceived / e.TotalBytesToReceive;
...
Raus kommt 0.2 => 20%, also das richtige Ergebnis.

???😖 0.2 sind 2 Zehntel von 1. 20 % sind 20 von 100 oder 0.2 *100

...spätestens jetzt sollte Dir einleuchten, das dir der Multiplikator 100 fehlt... 0.2*100 =20... machts klick?

Ich erlöse dich einfach aus Deinem Leid...

demo.cs

using System;
using System.Net;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;


public class Form1 : Form {

    private Button DLButton;
    private ProgressBar ProgressBar1;
    private Label ProgressDisplay1,
                  ProgressDisplay2,
                  StateDisplay,
                  UriLabel;
    private String DLUri = "http://addresses.loyce.club/Bitcoin_addresses_LATEST.txt.gz";


    public Form1() {
        this.Size = new Size(600,150);
        
        DLButton = new Button();
        DLButton.Text = "&Download";
        DLButton.Location = new Point(10, 10);
        DLButton.Click += new System.EventHandler(RunDownload);
        this.Controls.Add(DLButton);


        UriLabel = new Label();
        UriLabel.Text = DLUri;
        UriLabel.Location = new Point(100, 10);
        UriLabel.AutoSize = true;
        this.Controls.Add(UriLabel);


        ProgressDisplay1 = new Label();
        ProgressDisplay1.Text = String.Format("downloaded {0,12} of {1,12} bytes. {2,3} % complete...",0,0,0);  //e.BytesReceived,e.TotalBytesToReceive,e.ProgressPercentage
        ProgressDisplay1.Location = new Point(10, 40);
        ProgressDisplay1.AutoSize = true;
        this.Controls.Add(ProgressDisplay1);


        ProgressDisplay2 = new Label();
        ProgressDisplay2.Text = String.Format("FixpointPercentage:{0,7:f3} %",0);   // (e.BytesReceived*100.0/e.TotalBytesToReceive)
        ProgressDisplay2.Location = new Point(10, 60);
        ProgressDisplay2.AutoSize = true;
        this.Controls.Add(ProgressDisplay2);
        
        
        StateDisplay = new Label();
        StateDisplay.Location = new Point(200, 60);
        StateDisplay.Text = "Waiting for Start download...";
        StateDisplay.AutoSize = true;
        this.Controls.Add(StateDisplay);


        ProgressBar1 = new ProgressBar();
        ProgressBar1.Value = 0;
        ProgressBar1.Location = new Point(0, 80);
        ProgressBar1.Size = new Size(ClientSize.Width,20);
        this.Controls.Add(ProgressBar1);
        //ProgressBar1.ForeColor = ColorTranslator.FromHtml("#400040"); //only posible if VisualStyles not Enabled
        //ProgressBar1.Style = ProgressBarStyle.Continuous;  //only  posible if VisualStyles not Enabled
    }


    private void DownloadCompleted(object sender, AsyncCompletedEventArgs e){
        StateDisplay.Text = "File Complete...";
    }


    private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e){
        ProgressBar1.Value = e.ProgressPercentage;
        ProgressDisplay1.Text = String.Format("downloaded {0,12} of {1,12} bytes. {2,3} % complete...",
          e.BytesReceived,
          e.TotalBytesToReceive,
          e.ProgressPercentage
        );
        ProgressDisplay2.Text = String.Format("FixpointPercentage:{0,7:f3} %",(e.BytesReceived*100.0/e.TotalBytesToReceive));  //hier  Deine Prozentrechnung ,ganz  billig (auf 3 Nachkommastellen  wird  erst  durch die Formatanweisung {0,7:f3} gerundet!  einsetzen Parameter 0 Platzhalter, 7 Stellen rechtsbündig, Fixpoint 3 Nachkommastellen )
    }
    
    private void RunDownload(object sender, EventArgs e) {
        DLButton.Enabled = false;
        StateDisplay.Text = "Downloading...";
        WebClient wc = new WebClient();
        wc.DownloadFileCompleted += DownloadCompleted;
        wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
        wc.DownloadFileAsync(new Uri(DLUri), "test.bin");
    }
    
    static void Main() {
            Application.EnableVisualStyles();
            Application.Run(new Form1());
    }
}
0