Hallo,
ich habe ein Problem mit den Backgroundworker in c#.
Kurz zum Programm:
Das Programm soll 100 Ports auf eingehende Verbindungen überwachen, und
ausgeben, wer (welche IP und Port) auf den Port zugreift (61300 bis
61400).
Um die Ports zu überwachen erstelle ich 100 Backgroundworker und
TCPListener.
Das Programm funktioniert soweit auch, ABER:
Die Backgroundworker 0 bis 8 starten relativ schnell <1sek, und die
restlichen (9 bis 99) brauchen ca 1 Sekunde, bis sie gestartet sind.
Dann wird erst der Port geöffnet, und auf Verbindungen gewartet…
Warte ich jetzt bis alle 100 Backgroundworker gestartet sind, dann
funktioniert das Programm perfekt, aber das Warten dauert halt ewig…
Daher meine Fragen:
Gibt es einfachere Möglichkeiten um 100Ports zu überwachen auf
eingehende Verbindungen?
Warum sind die Backgroundworker so dermaßen langsam?
Die Ports werden über http://portchecker.co/ getestet, und ein umstellen
von Debug auf Release hat auch nix gebracht.
Mein System:
OS: Win 10 Pro x64
CPU: i7 6700k
RAM: 32GB RAM
GPU: GTX1080
Als Grundlage dient das Net.Framework 4.5.2
Und hier der Code:
Pascal H. schrieb:> Das Programm soll 100 Ports auf eingehende Verbindungen überwachen, und> ausgeben, wer (welche IP und Port) auf den Port zugreift (61300 bis> 61400).Pascal H. schrieb:> for (Int32 _Port = 61300; _Port <61401;_Port++)
Sicher dass das genau 100 Ports sind? :P
Darüberhinaus: Wenn man sich das Bild ansieht, dann sieht man, dass die
Worker 0 bis 8 (0, 2, 1, 6, 3, 7, 4, 5) nicht linear gestartet werden,
alle anderen aber sehr wohl (8, 9, 10, 11, 12, 13, ...).
Was könntest du daraus schließen?
Kaj schrieb:> Darüberhinaus: Wenn man sich das Bild ansieht, dann sieht man, dass die> Worker 0 bis 8 (0, 2, 1, 6, 3, 7, 4, 5) nicht linear gestartet werden,> alle anderen aber sehr wohl (8, 9, 10, 11, 12, 13, ...).> Was könntest du daraus schließen?
Das ist normal, die ersten acht Ports werden ihren Threads den logischen
CPU-Cores zugewiesen. Der eine arbeitet schneller, der andere langsamer.
Der TE könnte ja mal ganz einfach probieren die Ports auf nur drei oder
vier zu minimieren - dabei mal den einzelnen Cores zusehen, wie deren
Belastung / Zuweisung ist. Dann wird er verstehen wie ein
Backgroundworker arbeitet. Er hat da quasi 100 Threads am laufen - das
ist schon derb!
Ich würde das komplett anders anstellen. Ein (1!!) Thread /
Backgroundworker der den gesamten Adressbereich async abscannt und dann
in einem anderen Thread die einzelnen Ports, die einen Zugriff haben,
ausklabüstern.
Pascal H. schrieb:> Das Programm soll 100 Ports auf eingehende Verbindungen überwachen, und> ausgeben, wer (welche IP und Port) auf den Port zugreift (61300 bis> 61400).> Um die Ports zu überwachen erstelle ich 100 Backgroundworker und> TCPListener.
So ein krasser Unsinn. Typischer Fall von sinnloser
Threadvervielfachung, weil ich es nicht besser weiß...
Für sowas nimmt man natürlich einfache Sockets und nutzt dabei aus, dass
die sowieso asynchron agieren (können). Die nötigen Warte-Threads
erzeugen die dann selber.
Man macht also einfach 100(?! ;o) Sockets auf, ruft deren Methoden Bind,
Listen und BeginAccept() auf und schon ist man durch mit dem Thema.
c.m. schrieb:> ich kenne c# nicht, aber kann es sein das die initiale größe der listen> zu klein ist, und während der laufzeit "umständlich" vergrößert werden> muss?
Man macht einfach keine 100 Threads und 100 Sockets gleichzeitig auf!
So... das geht... ist aber ebenfalls Synchron:
Wie schon gesagt, gibt es wahrscheinlich einen besseren Weg als für
jeden Port einen eigenen Thread zu starten. Aber nicht unbedingt...
Bestimmt lohnt es sich, die Klasse ThreadPool anzusehen. Es gibt nur
einen ThreadPool pro Prozeß und mit den statischen Methoden der Klasse
läßt sich grob steuern, wieviele Threads gleichzeitig vorgehalten
werden. Wenn die Threads alle I/O-Bound sind, dann kann man schon sehr
viele erzeugen, ohne den Rechner lahmzulegen.
Der ThreadPool beobachtet die Threads, die er erzeugt. Wenn die nach
einer gewissen Zeit auf I/O warten, dann erlaubt er sich, neue zu
starten. Die genaue Strategie ist auch davon abhängig, ob .net auf einem
Client- oder Server-Betriebssystem läuft.
die 100 threads sind kein Problem für Windows. Aber die BackgroundWorker
sind komplexere Dinger die für Kommunikation mit dem UI Thread gedacht
sind. Die Version von Draco ist ok, die meiste Zeit warten die vielen
Threads auf ein IO Event und kosten nix.
Dieses Beispiel dürfte ein Paradebeispiel für Javascript mit Node.js
sein weil das von Hause aus asynchron und Eventgesteuert arbeitet.
guest schrieb:> Ist ja nicht so, daß .NET nicht auch asyncron könnte
Schreibt ja Draco:
> Ich sagte ja, ich mach noch ein mit asynchron.
Aber da kommt dann jeweils ein IAsyncResult raus,
also werden es wieder 100 Threads oder Tasks.
Nur dass man die nicht so offensichtlich selbst erzeugt.
Wobei ich den Unterschied zwischen Threads und Tasks nicht spontan
erklären könnte. Vielleicht brauchen Tasks weniger Ressourcen als
Threads?
Hi,
.NET zeigt dieses Verhalten stets bei Threads, die sich aus dem
ThreadPool bedienen. Dazu gehören auch der BackgroundWorker sowie das
komplette Task-API. Sind alle logischen Kerne mit Threads ausgelastet,
dann wird jeder weitere Thread nur noch zeitverzögert gestartet, so
500-1000 ms nach meinen Beobachtungen.
Dies macht ja auch normalerweise Sinn, um Überlastungen durch zu viele
gleichzeitige Threads zu vermeiden. Wahrscheilich also eine
Optimierungsstrategie von .NET.
Umgehen kann man dies, indem man direkt die Thread-Klasse benutzt. Dies
macht hier und da mehr Arbeit, aber das beobachtete Verhalten tritt dort
nicht mehr auf, und das Programm verhält sich wie früher das WinAPI.
Ob das alles Sinn macht steht selbstverständlich auf einem anderen
Blatt.
Ich habe jedenfalls diese Methode Threads zu erzeugen, nur ein einziges
mal benötigt.
Gruß,
Oliver