none
NullReferenceException in Parallel.ForEach RRS feed

  • Frage

  • Hallo,

    folgender Code bringt in der Parallel.ForEach einen NullReferenceException,

    mit normaler foreach kommt kein Fehler:

            public Boolean insertListOfPoints(IList<BeanPunkte> listOfPunkte)
            {
                if (listOfPunkte == null) return true;
                if (listOfPunkte.Count == 0) return true;
                Parallel.ForEach<BeanPunkte>(listOfPunkte, item =>
                {
                    item.matriksinsert = true; // bei der Exception ist item == null !?
                    item.eingelesenam = DateTime.Now;
                });
                return insertAndCommitListOfBean(listOfPunkte.ToList<Object>()); // fügt die Liste von Punkten in die DB ein (Update)
            }
    ...mmm... Wie kann das bei einer ForEach sein?
    Dienstag, 21. Februar 2012 05:12

Alle Antworten

  • ... Au backe, in der listOfPunkte sind tatsächlich "null-Objekte" drinn, dürften aber nicht,

    da ich vor dem Einfügen in der Liste die BeanPunkte auf null prüfe:

                            Parallel.ForEach<CADdyPunkt>(quelle.DBKPointList.Values, cADdyPunkt =>
                            {
                                if (!allPunkteFromDB.ContainsKey(cADdyPunkt.Punktnummer))
                                {
                                    newPunkt = ToolsPunkte.getBeanPunktFromCADdyPunkt(cADdyPunkt, idProject);
                                    if (newPunkt != null)
                                        newPoints.Add(newPunkt);
                                    else
                                        newPunkt = null; // Test für den Lauf, wird nie angesprungen
                                }
                            });

    Das eigenartige ist, dass immer die Einträge mit folgendem Indexen null sind: 32, 128, 1024, 2048 !

    Kann das an der Partitionierung in der Parallel.ForEach liegen?

    Dienstag, 21. Februar 2012 05:29
  • ... hab erst einmal ein QuickAndDirty dafür gefunden:

    // nach der Parallel.ForEach

    while (newPoints.Contains(null)) { newPoints.Remove(null); }

    aber dir Frage bleibt trotzdem woher kommen die "blöden" null-Werte in der Liste

    und wie verhindert man diese?

    Dienstag, 21. Februar 2012 07:07
  • Hallo Mario,

    Dein Problem dürfte daran liegen, dass Du keine threadsicherere Auflistung hast.
    Und selbst mit der kannst Du so nicht auf darauf zugreifen.

    Selbst wenn ContainsKey noch false liefert, so könnte ein zweiter Thread eben
    jenen newPunkt erzeugen und einfügen.
    Und sind mehr als zwei aktiv, könnte das mehrfach passieren.

    Zu den 32, ... 2048:
    Das wird sich in dem Moment manifestieren, wenn die Liste vergrößert werden muss,
    da die internen Strukturen dabei üblicherweise verdoppelt werden.

    Du solltest erstmal auf Parallel verzichten und Dich in die Grundlagen einarbeiten:
    Task Parallel Library

    Im allgemeinen gilt eh:
    Für das Durchlaufen einer Auflistung mit minimaler Verarbeitung lohnt eine Parallelisierung nicht.

    Gruß Elmar

    Dienstag, 21. Februar 2012 08:42
    Beantworter
  • Hallo Elmar,

    ab welchen Größenordnungen (List.Count) lohnt sich den dann

    "übern Daumen" die Parallelisierung?

    Gruß Mario

    Dienstag, 21. Februar 2012 12:57
  • Hallo Mario,

    für ein reines Kopieren / Übertragen wie Du es oben andeutest, lohnt es i. a. gar nicht,
    denn das würde eine Synchronisierung benötigen, siehe dazu:
    Potenzielle Fehler bei Daten- und Aufgabenparallelität

    Erst wenn das Erzeugen (bzw. Übertragen) mit aufwändigeren Aktionen
    verbunden ist kann sich das lohnen.
    Aber dazu will dann das Verwenden von Sperren, Datenparallelität usw.  verstanden sein.

    Davon ist oben aber nichts zu sehen, deswegen der Ratschlag sich zunächst in die Grundlagen einzuarbeiten,
    denn bei TPL / PLINQ ist nicht damit getan, ein Parallel. zu schreiben.

    Gruß Elmar

    Dienstag, 21. Februar 2012 23:57
    Beantworter