none
Parallel.For kombiniert mit ConcurrentBag scheint nicht thread-safe zu sein RRS feed

  • Frage

  • Ich verwende Parallel.For zum ersten Mal um Listen zu füllen (ich verwende hier ConcurrentBag)
    Aber es scheint, dass ConcurrentBag auch Daten von anderen Threads erhält.
    Hintergrund:
    Ich habe eine riesige Datenmenge an x-Werten. Die Aufgabe ist, sie auf verschiedene Listen zu verteilen.
    Wie könnte ich das lösen?
    Mein Ansatz bisher:

    public static void getNearXvalues(double deltaX, double xCenter, double[] xSource, out double[] xNear)
    {
        var xList = new ConcurrentBag<double>();
    
        Parallel.For(0, xSource.Length, i =>
        {
            if((Mat.Abs(xCenter-xSource)<deltaX)
            {
                xList.Add(xSource[i]);
            }
        });
        xNear = xList.ToArray();
    }

    for(ix=-100;ix<=100;ix++)
    {
      getNearXvalues(1.0, ix, xSource, out xNear[ix]);
    }
    // xSource enthält zB. 1Mio Datensätze, der Aufruf verteilt die Werte im Beispiel auf 200 Listen






    • Bearbeitet wolfgangh Freitag, 11. Juni 2021 11:31
    Freitag, 11. Juni 2021 06:24

Antworten

  • Hallo

    Nein, noch immer nicht ;)

    Du rufst aus einem Thread 200x eine Arbeit auf, die dann die Werte parallel verarbeitet.

    Du müsstest eigentlich eine Schleife erstellen, die dann lauter Tasks erstellt & diese dann abarbeitet.

    Ich habe im Moment keine Umgebung bei der Hand, aber der Code müsste so in etwa laufen

    async Task<int> LongTask1() { 
      ...
      return 1; 
    }
    
    {
       List<Tasks> listOfTasks = new List<Taks>
       for (ix = -11; ix<100; ix++)
    {
        Task<int> t1 = LongTask1();
        listOfTasks.Add(t1);
    }
       await Task.WhenAll(listOfTasks.ToList);
      
    }

    Damit werden die Tasks mal alle ohne Ausführung in eine Liste geschrieben (keine Zeit Verzögerung) und dann kümmert sich das Framework um die Taskausführung.

    Hoffe das hilft Dir

    PS: Du könntest aber auch genauso den Code aus Deinem ersten Beispiel hernehmen & nach der Arbeit in x Listen aufteilen.

    Warum Du so viele Listen brauchst, ist mir unklar, aber es wird sicher einen Grund haben.
    Du solltest bei so vielen Listen nämlich aufpassen, dass genug freier Speicher zur Verfügung steht.

    Freitag, 11. Juni 2021 15:21

Alle Antworten

  • Hallo

    Ja, das ist auch der Sinn Deines codes.

    Lt. Deinem Code schreibst Du aus mehreren Threads in eine "Liste".

    Diese "Liste" (ConcurrentBag) ist Thread Safe. D.h. Du musst Dich nicht um das Sperren bei mehreren Zugriffen kümmern.

    Was Du machen müsstest, wäre verschiedene Threads zu erstellen und innerhalb dieses Threads eine Liste füllen (diese muss dann nicht Thread safe sein) - Könnte als auch eine einfache List<double> sein.

    Thread.Start Method (System.Threading) | Microsoft Docs

    Das Problem dabei ist eher, dass Du nicht wirklich bestimmen kannst, wie viele Threads laufen (sollen) Da das Framework im Hintergrund steuert.

    Auch bei Parallel.... Kannst Du nicht die definitive Thread Anzahl vorhersagen. Dabei gilt die Faustregel, je mehr physische Kerne, um so mehr Threads.

    Die Frage ist eher, warum jeder Thread eine eigene Liste erzeugen soll...

    lg

    Freitag, 11. Juni 2021 10:44
  • Ich habe meine Frage präzisiert.
    Ich dachte, dass ich verschiedene Threads erstelle, indem ich die Funktion in einer Schleife aufrufe (hier 200-mal).
    Freitag, 11. Juni 2021 11:34
  • Hallo

    Nein, noch immer nicht ;)

    Du rufst aus einem Thread 200x eine Arbeit auf, die dann die Werte parallel verarbeitet.

    Du müsstest eigentlich eine Schleife erstellen, die dann lauter Tasks erstellt & diese dann abarbeitet.

    Ich habe im Moment keine Umgebung bei der Hand, aber der Code müsste so in etwa laufen

    async Task<int> LongTask1() { 
      ...
      return 1; 
    }
    
    {
       List<Tasks> listOfTasks = new List<Taks>
       for (ix = -11; ix<100; ix++)
    {
        Task<int> t1 = LongTask1();
        listOfTasks.Add(t1);
    }
       await Task.WhenAll(listOfTasks.ToList);
      
    }

    Damit werden die Tasks mal alle ohne Ausführung in eine Liste geschrieben (keine Zeit Verzögerung) und dann kümmert sich das Framework um die Taskausführung.

    Hoffe das hilft Dir

    PS: Du könntest aber auch genauso den Code aus Deinem ersten Beispiel hernehmen & nach der Arbeit in x Listen aufteilen.

    Warum Du so viele Listen brauchst, ist mir unklar, aber es wird sicher einen Grund haben.
    Du solltest bei so vielen Listen nämlich aufpassen, dass genug freier Speicher zur Verfügung steht.

    Freitag, 11. Juni 2021 15:21