1. #1

    Registriert seit
    03.09.2015
    Beiträge
    135
    Thanked 55 Times in 40 Posts

    Standard Asynchrone Webanfragen

    Hi Leute,

    mit meiner PostRequest()-Methode tätige ich um 10 Webrequests die Sekunde:

    private string pageSource;
    private WebResponse response;

    public string PostRequest(string url, string formParams)
    {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.CookieContainer = container;
    request.Proxy = null;
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = "POST";
    byte[] bytes = Encoding.ASCII.GetBytes(formParams);
    request.ContentLength = bytes.Length;

    using (Stream os = request.GetRequestStream())
    {
    os.Write(bytes, 0, bytes.Length);
    }

    request.BeginGetResponse(new AsyncCallback(finishWebRequest), request); // Mit AsyncCallback

    using (StreamReader sr = new StreamReader(response.GetResponseStream()))
    {
    pageSource = sr.ReadToEnd();
    }

    showPageSource(pageSource);

    return pageSource;
    }

    private void finishWebRequest(IAsyncResult result)
    {
    response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
    }


    Die Methode finishWebRequest() habe ich von Stackoverflow übernommen: c# - How to use HttpWebRequest (.NET) asynchronously? - Stack Overflow

    Aber selbst ohne das Asynchrone erziele ich das gleiche Ergebnis. Ist mein Verfahren ohne die finishWebRequest()-Methode vielleicht schon einfach so asynchron? Oder wieso macht das keinen Unterschied? Und gibt es Möglichkeiten die Anfragen noch schneller durchzuführen? Ich nutze übrigens .NET 4.5.2.

    Mein Code ohne asynchrone Vorgehensweise, welcher das gleiche Ergebnis erzielte:
    Spoiler:

    private string pageSource;
    private WebResponse response;

    public string PostRequest(string url, string formParams)
    {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.CookieContainer = container;
    request.Proxy = null;
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = "POST";
    byte[] bytes = Encoding.ASCII.GetBytes(formParams);
    request.ContentLength = bytes.Length;

    using (Stream os = request.GetRequestStream())
    {
    os.Write(bytes, 0, bytes.Length);
    }

    WebResponse response = request.GetResponse(); //Ohne AsyncCallback

    using (StreamReader sr = new StreamReader(response.GetResponseStream()))
    {
    pageSource = sr.ReadToEnd();
    }

    showPageSource(pageSource);

    return pageSource;
    }

    Geändert von Negok (02.08.2016 um 20:55 Uhr) Grund: Überflüssige Inline-Doku entfernt
    Mfg

    .\

  2. #2
    Avatar von DMW007
    Registriert seit
    15.11.2011
    Beiträge
    6.080
    Thanked 9.118 Times in 2.995 Posts
    Blog Entries
    5

    Standard AW: Asynchrone Webanfragen

    Ich vermute das macht sehr wenig bis gar nichts aus, weil letztendlich nur die Antwort asynchron geladen wird. Der restliche Code wird synchron abgearbeitet. Für den konkreten Einzelfall lässt sich dazu wenig sagen, weil das von verschiedenen Faktoren abhängt. Am entscheidendsten dürfte die Größe der Antwort sein. Bei 10 Anfragen pro Sekunde vermute ich mal nicht all zu groß. Dementsprechend wird das parallelisieren auf diese Art und Weise kaum einen Geschwindigkeitsvorteil bringen. Wesentlich besser dürfte dagegen sein, den gesamten Vorgang in separate Threads auszulagern:


    new Thread((ThreadStart)delegate {
    var request = (HttpWebRequest)WebRequest.Create(url);
    // ...
    }).Start();

    Damit lagerst du alles aus und bist dementsprechend nur auf deine Hardware limitiert. Bedenke aber, dass nun das Netzwerk bzw. Genauer die Internetanbindung dein nächster potenzieller Flaschenhals ist. Je nach Geschwindigkeit deiner DSL-Leitung kann es sein, dass du mit den 10 Anfragen dort schon am Limit bist. Auch dazu lässt sich ohne Details nichts sagen. Im Zweifel den maximalen Datendurchsatz mit Tests messen und prüfen, wie weit dieser mit deiner Software ausgelastet wird.

    Generell wäre ich jedoch vorsichtig mit deinem Vorhaben. Abfragelimits und Firewalls, welche die Anfragen anhand bestimmter Limits begrenzen, sind mittlerweile eigentlich Standard. Die stetige Zunahme von DoS/DDoS-Angriffen spielt dabei eine entscheidende Rolle. Ich weiß ja nicht was du da konkret machst, aber 10 Anfragen pro Sekunde sind schon ziemlich viel. Nicht dass die das für einen DoS-Angriff halten bzw. als solchen erleben. Je nachdem wie gut die Systeme betreut werden fällt das recht schnell auf, wenn jemand so viele Anfragen abschickt. Gerade bei kleineren Infrastrukturen geht die Serverlast dabei schnell nach oben. Wenn du nicht befugt bist das zu tun, wirst du möglicherweise Blockiert. Im schlimmsten Falle kann das auch mit einer Strafanzeige enden. Nur als kleiner Hinweis am Rande.


  3. The Following User Says Thank You to DMW007 For This Useful Post:

    Negok (02.08.2016)

  4. #3

    Registriert seit
    02.01.2013
    Beiträge
    879
    Thanked 458 Times in 313 Posts

    Standard AW: Asynchrone Webanfragen

    Mir scheint, als ob das asynchrone Codebeispiel sowieso falsch ist. BeginGetResponse blockiert ja nicht, bis die Response da ist, sondern die Ausführung geht sofort weiter. Anschließend wird auf die Response zugegriffen... aber ist sie wirklich schon da? Wenn die Antwortszeit sehr gut ist (z.B. Testserver auf Entwicklungsrechner), vielleicht, wenn sie unter Realbedinungen schlecht ist, vielleicht auch nicht. Im Beispielcode bei MS ist vor der Bearbeitung der Response etwa ein WaitForSingleObject eingefügt... ohne mit der Bearbeitung der Response zu warten, bis sie auch garantiert da ist, ist ein Glücksspiel.

  5. The Following User Says Thank You to freulein For This Useful Post:

    Negok (03.08.2016)

  6. #4

    Registriert seit
    03.09.2015
    Beiträge
    135
    Thanked 55 Times in 40 Posts

    Standard AW: Asynchrone Webanfragen

    Hey,

    ich habe am Anfang echt ein wenig gezweifelt, ob Multithreading wirklich das Richtige sei. Denn einige Zungen im Internet verwiesen von dem Thema doch wieder auf "asynchrone Verarbeitung". Das erste Ergebnis war jedoch ganz super:

    1.000 GET-Anfragen auf Google.de:
    Asynchrone Variante: 01:28
    Multithread-Variante: 00:32

    Test-Umgebung: Win10, CPU i7-4510U 2x2,6GHz, 8GB RAM, 100MBit/s (nie getestet)

    Von der HttpWebRequest-Klasse bin ich auch ab. Der WebClient bringt die notwendingen Funktionen an sich mit, ohne dass ich die Bytes selber konvertieren muss. An sich aber trotzdem gut für das Verständnis gewesen. Die asynchrone Variante habe ich nun hoffentlich auch verbessert.


    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace WebRequest_Multithreading
    {
    public partial class Form1 : Form
    {
    //Listen, die die HTML-Responses speichern
    private List<string> resultsAsynchron = new List<string>();
    private List<string> resultsMultithread = new List<string>();

    private string url = "https://www.google.de";
    private WebClient webClient = new WebClient();

    public Form1()
    {
    InitializeComponent();
    }

    private async void btnDownload_Click(object sender, EventArgs e)
    {
    resultsMultithread.Clear();
    resultsAsynchron.Clear();

    for (int i = 0; i < 1000; i++)
    {
    if (rbAsynchron.Checked) //rb = Radio-Button
    {
    resultsAsynchron.Add(await downloadAsynchron());
    }
    else if (rbMultithread.Checked)
    {
    var thread = new Thread(downloadMultithread);
    thread.Start();
    }
    }
    }

    private async Task<string> downloadAsynchron()
    {
    return await webClient.DownloadStringTaskAsync(url);
    }

    public void downloadMultithread()
    {
    WebClient wclient = new WebClient();
    resultsMultithread.Add(wclient.DownloadString(url));
    }
    }
    }


    Auffällig ist, dass die Threads nur zu Beginn sehr hochspringen und diese im nachhinein ungefähr auf das selbe Level wie die asynchrone Variante kommen. Die grüne Startlinie habe ich ein wenig zu weit rechts eingezeichnet, sorry.


    Wie ist das zu erklären? Kann ich dem nicht entgegen wirken? Er schießt zu Beginn irgendwie 100-300 Threads auf ein mal los, den Rest lässt er dann allerdings gefühlt nacheinander abarbeiten.

    Die Internetlast ist hierbei ziemlich gleichbleibend geblieben:


    Bei höheren Abfragemengen (z.B. 5.000 Stück) schmiert das Programm beim Starten auch irgendwann komplett ab:


    Da wollte ich mich allerdings selber noch mal schlau machen.

    LG
    Geändert von Negok (08.08.2016 um 22:50 Uhr) Grund: Code-Tags angepasst
    Mfg

    .\

  7. The Following User Says Thank You to Negok For This Useful Post:

    DotNet (10.08.2016)

  8. #5

    Registriert seit
    02.01.2013
    Beiträge
    879
    Thanked 458 Times in 313 Posts

    Standard AW: Asynchrone Webanfragen

    Es ist mir unklar, wozu ein Programm wie das gelistete, das praktisch im selben Moment 1000 Abfragen an die selbe URL abschickt, gut sein soll. Wenn die URL die im Listing angeführte ist, wird man relativ schnell sowieso blockiert, google wertet sowas nämlich als Angriff. Das kann zu einer Meldung beim Internetprovider führen, wenn das regelmäßig passiert. Mein Vorschlag: Wenn Du bloß verschiedene Programmierverfahren testen willst, setze einen eigenen Webserver auf, und benutze dann die localhost-URL. Was Du da machst wäre mir zu gefährlich. DMW007 hat dazu ja schon einiges gesagt. Eine Hilfestellung darüber hinaus ist schwierig, wenn man nicht genau weiß, was Du eigentlich wozu genau machen willst.

  9. The Following 2 Users Say Thank You to freulein For This Useful Post:

    DotNet (11.09.2016), Negok (09.08.2016)

  10. #6
    Avatar von DotNet
    Registriert seit
    10.06.2015
    Beiträge
    661
    Thanked 316 Times in 185 Posts

    Standard AW: Asynchrone Webanfragen

    Der Vorteil bei dem lokalen Server ist zudem, dass du keine Flaschenhälse hast. Dieser dürfte vor allem beim Netzwerk liegen. Internetverbindungen schaffen heutzutage bei Privatpersonen im besten Falle 150Mbit/s im Downstream. Wobei das natürlich der Idelfall ist. Schlechter Ausbau in ländlicheren Regionen, alte Verkabelungen und dicht besiedelte Städte sorgen dafür, dass viele nicht annähernd an die 150Mbit/s heran kommen. Mit einem lokalen Webserver gibt es diese Probleme gar nicht, weil du kein Netzwerk benötigst, alles läuft über die Loopback-Schnittstelle. Die einzige Limitierung ist nun die Hardware des Computers. Und da gibt es keine Probleme, wenn du ein halbwegs leistungsfähiges System hast, wovon ich bei Entwicklern ausgehe.

    Für den Webserver würde ich dir einen High-Performant event-basierten Server wie nginx empfehlen. Diese verbrauchen nur einen Bruchteil der CPU- und Ramleistung von klassischen threadbasierten Webservern wie dem Apache. Mit ersterem kannst du also viel mehr Anfragen auf der gleichen Hardware ausführen.

    Im Krieg gibt es keine Gewinner, nur Verlierer!

  11. The Following User Says Thank You to DotNet For This Useful Post:

    Negok (11.09.2016)

Diese Seite nutzt Cookies, um das Nutzererlebnis zu verbessern. Klicken Sie hier, um das Cookie-Tracking zu deaktivieren.