Parallel For Problem

06/07/2018 16:21 Ludder231#1
Hi,

es kennen vielleicht einige das Problem, dass mit einer Parallel For die Fehlermeldung "Die Auflistung wurde geändert" bekommt.

In der Prarallel For wird auf eine webseite connected und dort per regex daten ausgelesen und dann ein objekt gefüllt. dieses objekt wird einer list<> hinzugefügt.

Wie kann ich den Fehler verhindern?

[Only registered and activated users can see links. Click Here To Register...]
06/11/2018 12:03 Xio.#2
zb mit lock

Wenn du es richtig machen willst solltest du googlen [Only registered and activated users can see links. Click Here To Register...]
06/11/2018 15:22 warfley#3
Wenn du threading verwendest solltest du dir vorher wenigstens durchlesen was Racing conditions sind, wie Critical Sections (locks), Barriers, Mutexe, etc funktionieren. Ich weiß das in .Not Threading sehr einfach umzusetzen ist, das heißt aber trozdem nicht das es einfach ist. Bei Threading musst extrem aufpassen, denn fehler aufgrund von Racing Conditions zu finden ist extrem wiederlich (und z.T. extrem schwer bis unmöglich im debugger zu finden).

Ein einstieg dafür ist: [Only registered and activated users can see links. Click Here To Register...].

In deinem Fall muss ja nur das HTTP webrequest parallelisiert werden, der rest kostet ja keine Zeit. Das heißt man kann den restlichen code serialisieren, z.B. mit einer Barrier
Code:
Parallel.For(...
  html = ...
  barrier[i].SignalAndWait();
  // no other of the working threads is currently running this section, and mainthread is also paused
  ...
  retHorse.AddData(h);
  barrier[i].SignalAndWait();
}); // for end
for (int i=0; i<barrier.length; i++) {
  barrier[i].SignalAndWait(); // Wait for webrequrest
  barrier[i].SignalAndWait(); // Wait for List addition
}
Du könntest auch eine Lock verwenden (ist wahrscheinlich sogar simpler) dabei kannst du aber nicht über das scheduling bestimmen. Mit Barriers übernimmt der Mainthread die aufgabe des Lock schedulings (was man eventuell haben möchte oder auch nicht). In diesem fall werden die threads aufsteigend gescheduled.

PS: Da eventuell exceptions auftreten können ist ein Try-Finally für die Barrier locks empfehlenswert
06/11/2018 15:57 Ludder231#4
Danke schon mal. Bräuchte ich nicht sogar schon vor der html-variable ein lock/barrier weil es ja sonst möglich ist das zu einem Pferd die falsche html Seite geparsed wird weil sie von dem nachfolgendem Thread überschrieben wird weil der aktuelle Thread länger dauert weil die Webseite mal nicht so schnell antwortet?
06/11/2018 16:23 warfley#5
Quote:
Originally Posted by Ludder231 View Post
Danke schon mal. Bräuchte ich nicht sogar schon vor der html-variable ein lock/barrier weil es ja sonst möglich ist das zu einem Pferd die falsche html Seite geparsed wird weil sie von dem nachfolgendem Thread überschrieben wird weil der aktuelle Thread länger dauert weil die Webseite mal nicht so schnell antwortet?
Stimmt das habe ich gar nicht gesehen. Das lässt sich aber ganz einfach lösen, definiere html einfach als lokale variable im for.
Lokale variablen werden auf den Stack gepusht, und jeder Thread hat seinen eigenen thread. Globale Variablen und der Heap sind geshared, daher alles was dein thread nicht selbst erzeugt ist eine potentielle gefahr.
Wenn du das Lock vor das HTML machst, dann führst du serialisiert die threads aus, das ist das selbe als würdest du ein normales for nehmen, nur mit mehr overhead. (also insgesammt eine eher schlechte Idee)

Genau das meinte ich mit Multithreading ist zwar einfach umzusetzen aber trozdem nicht leicht. Dein fall ist noch recht einfach, da du einfach html lokal definieren kannst, aber wenn du auf mehrere globale daten zugreifen musst, desto mehr locks benötigst du und dann kommt plötzlich noch die möglichkeit für Deadlocks, wenn Thread 1 auf Lock 1 wartet aber das erst von Thread 2 gelöst werden kann der auf Lock2 wartet was von Thread 1 gehalten wird.
06/11/2018 17:26 Serraniel#6
Alternativ ne ConcurrentList verwenden, bei der u. A. das Hinzufügen von Elementen Threadsafe ist (ich nehme an, dass das Verändern der Liste den Fehler verursacht?): [Only registered and activated users can see links. Click Here To Register...]