Entwickler-Ecke

Basistechnologien - Wie und womit? Waithandles evtl.?


BlackMatrix - Sa 25.09.10 20:31
Titel: Wie und womit? Waithandles evtl.?
Hallo.

Mein Programm holt Links aus einem Quelltext, ruft diese sequentiell hintereinander auf und muss danach eine bestimmte Zeit warten, bis es erneut einen Aufruf tätigen darf. Die Zeit bis es wieder aufrufen darf, wird erst im Quelltext der Links ersichtlich.

Nun frage ich mich, wie ich das möglichst resourcenschonend hinbekomme, vielleicht sogar sequentiell, aber da fiel mir bisher keine Lösung für ein.

Jedenfalls habe ich jetzt nachdem der Quelltext der Links geladen wurde ParamterizedThreads gestartet und denen den Link,die Wartezeit und die ThreadID übergeben. Am Ende warte ich, bis alle Threads die Methode Set() aufrufen um den Mainthread wieder freizugeben:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
                        ManualResetEvent[] threads = new ManualResetEvent[links.Count];

                        for (int i = 0; i< links.Count; i++)
                        {
                            threads[i] = new ManualResetEvent(false);

                            parameter[0] = wartezeit;
                            parameter[1] = url;
                            parameter[2] = i;

                            ThreadPool.QueueUserWorkItem(Aufruf, parameter);
}
 WaitHandle.WaitAll(threads);


Klappt ja soweit ganz gut, aber 1. Problem, dass ist sicher nicht resourcenschonend, weil ja für jeden Link Threads gestartet werden und 2. wenn es mehr als 64 Link sind, streikt mein C# Programm und bringt eine NotSupportedException.

Jemand eine Lösung?

MfG


Kha - Sa 25.09.10 21:12

Das hört sich aber verdächtig nach Automation einer Webseite an, erlaubt die das auch :gruebel: ? Wie auch immer, was spricht gegen einen ganz normalen Timer, den du auf die kleinste Wartezeit stellst?


BlackMatrix - So 26.09.10 13:30

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Das hört sich aber verdächtig nach Automation einer Webseite an, erlaubt die das auch :gruebel: ?


Ich wüsste nicht was dagegen spricht, ich crawle nicht, mache mir nur die Bedienung durch mein Programm einfacher.

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Wie auch immer, was spricht gegen einen ganz normalen Timer, den du auf die kleinste Wartezeit stellst?


Kleinste Wartezeit? Meinst du evtl. größte Wartezeit um dann den Mainthread weiterlaufen zu lassen?
Wenn du das so meinst, müsste ich ja die Wartezeiten in eine Liste packen und dann der Methode den Parameter übergeben, dass es die größte ist, oder? Und dann könnte ich ja den Schritt weitergehen, die Wartezeiten+Links abspeichern, nach Wartezeiten ordnen (und ausrechnen) und dann sequentiell immer Warten,Webrequest,Warten,... Oder macht das Erzeugen von vielen Threads, die eh nur warten und dann einen Aufruf tätigen, resourcentechnisch nichts aus?

MfG BlackMatrix


Kha - So 26.09.10 14:17

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Ich wüsste nicht was dagegen spricht
Entweder die AGB erlauben es oder sie tun es nicht.

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Und dann könnte ich ja den Schritt weitergehen, die Wartezeiten+Links abspeichern, nach Wartezeiten ordnen (und ausrechnen) und dann sequentiell immer Warten,Webrequest,Warten,...
Genau so meinte ich es, damit kommst allein mit dem Hauptthread aus. Aber du musst natürlich mit der kleinsten Wartezeit anfangen, nicht mit der größten.

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Oder macht das Erzeugen von vielen Threads, die eh nur warten und dann einen Aufruf tätigen, resourcentechnisch nichts aus?
Normalerweise würde ich sagen, dass sinnlos wartende Threads überhaupt kein Problem sind, solange wir nicht über einen Webserver sprechen, aber da du nicht mehr über die Exception verrätst ;) ...


BlackMatrix - So 26.09.10 16:17

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Genau so meinte ich es, damit kommst allein mit dem Hauptthread aus. Aber du musst natürlich mit der kleinsten Wartezeit anfangen, nicht mit der größten.


Da werde ich das mal so probieren. Kannst du mir noch einen Tipp geben, wie ich das realisiere? ArrayList oder ne Klasse mit Wartezeit und Link und dann irgendwie sortieren oder doch ganz anders?


Kha - So 26.09.10 16:42

Ich würde die Wartezeiten direkt in den Zeitpunkt umrechnen und dann in einer

C#-Quelltext
1:
SortedList<DateTime, string (* Uri *)>                    

speichern. Wenn mehrere Links zur gleichen Zeit abgefragt werden müssen, müsstest du statt einer URL wohl gleich eine List<string> pro DateTime speichern.


BlackMatrix - So 26.09.10 17:50

Wow ist die SortedList einfach. Da muss ja nicht mal mehr sortiert werden :]

Klappt wunderbar, hier mein Code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
            SortedList<DateTime, string> datetimeLinks = new SortedList<DateTime, string>();

            foreach (string link in links)
            {
                datetimeLinks.Add(DateTime.Now.AddSeconds(wartezeit), url);
            }

            foreach (KeyValuePair<DateTime, string> datetimeLink in datetimeLinks)
            {
                TimeSpan wartezeit = datetimeLink.Key - DateTime.Now;

                if (wartezeit.TotalSeconds > 0)
                    Thread.Sleep(wartezeit);

                http.GET(datetimeLink.Value);
}


Habs noch ein klein wenig abgeändert, habe TimeSpan draus gemacht, anstatt DateTime


BlackMatrix - Di 28.09.10 00:40

Kann ich die Keys irgendwie noch genauer definieren, denn in seltenen Fällen kommt es vor, dass 2 gleiche Timespans abgespeichert werden müssen und dann kommt eine Exception.

Ich frage mich aber, wie das sein kann, denn die TimeSpans haben Werte wie diese: 00:30:05.1875000 und sind für meine Begriffe so genau, dass ich da niemals so oft schon hätte draufstoßen können.

Oder sollte ich dann doch wieder zu DateTime und Liste greifen?


Kha - Di 28.09.10 18:23

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Wenn mehrere Links zur gleichen Zeit abgefragt werden müssen, müsstest du statt einer URL wohl gleich eine List<string> pro DateTime speichern.
;) ?


BlackMatrix - Di 28.09.10 23:17

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Wenn mehrere Links zur gleichen Zeit abgefragt werden müssen, müsstest du statt einer URL wohl gleich eine List<string> pro DateTime speichern.
;) ?


Ich kapier das nicht, wie füge ich denn da den ValueWert der Liste hinzu, wenn da schon ein Key in der SortedList ist.

Ich mein, ich muss doch der SortedList als 2. Parameter eine Liste übergeben und das kann ich doch nur, wenn ich prüfe, ob in der SortedList schon ein Eintrag ist, wenn ja den Eintrag herausholen, ne neue Liste erstellen und beide in die Liste einfügen und am Ende wieder übergeben oder geht das auch einfacher?

MfG


Kha - Mi 29.09.10 18:24

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
wenn ich prüfe, ob in der SortedList schon ein Eintrag ist, wenn ja den Eintrag herausholen
Bis dahin stimmt's, aber wenn du dann die bisherige Liste in den Händen hältst, fügst du einfach den neuen Eintrag ein und bist fertig.


BlackMatrix - Do 30.09.10 01:39

So ganz geheuer ist mir das nicht. Was sagst du hierzu? Stimmt das so oder ist das falsch?


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
 SortedList<DateTime, List<string>> datetimeLinks = new SortedList<DateTime, List<string>>();
                            [...]
                            {
                                List<string> liste = new List<string>();
                                if (datetimeLinks.Keys.Contains(wann))
                                {
                                 datetimeLinks.Values[datetimeLinks.IndexOfKey(wann)].Add(link);
                                }
                                else
                                {
                                    liste.Add(link);
                                    datetimeLinks.Add(wann, liste);
                                }
                            }


Kha - Do 30.09.10 22:38

liste würde ich erst dort erzeugen, wo sie gebraucht wird, aber ansonsten stimmt das so :) .