Implementierung parallel_for Gut/Schlecht



  • Hallo zusammen,

    da ich auf Anhieb nicht viel zur Implementierung einer "parallel_for" Funktion gefunden habe, habe ich mich daran gemacht selbst eine zu erstellen. Nun würde ich gerne von euch wissen ob diese so wie sie ist brauchbar ist oder Fehler enthält die sich später rechen könnten.

    #include <vector>
    #include <iostream>
    #include <thread>
    #include <functional>
    #include <mutex>
    
    using namespace std;
    
    template <typename T, typename funcT>
    void parallel_for(T start, T end, size_t maxThreads, funcT func)
    {
    	vector<thread> threads;
    	T position = start;
    	mutex positionMutex;
    
    	auto workerFunction = [&](){
    		while (position < end)
    		{
    			positionMutex.lock();
    			int number = position;
    			position++;
    			positionMutex.unlock();
    
    			func(number);
    		}
    	};
    
    	for (size_t threadCount = 0; threadCount < maxThreads; threadCount++)
    	{
    		threads.push_back(thread(workerFunction));
    	}
    
    	for (size_t threadIndex = 0; threadIndex < threads.size(); threadIndex++)
    	{
    		threads.at(threadIndex).join();
    	}
    }
    

    Aufgerufen wird sie z.B. so:

    parallel_for(0, 8, 8, [](int i){
    		this_thread::sleep_for(chrono::milliseconds(1000));
    		cout << "Nr " << i << " ist fertig.\n";
    	});
    

    Gruß wolfsberger



  • Threads in einer parallel_for-Funktion zu starten und wieder zu beenden ist wohl nicht wirklich sinnvoll. Threads sind teuer.

    Da https://www.threadingbuildingblocks.org/ gibts eine brauchbare Implementierung.



  • Danke, das sieht sehr interessant aus, es scheint genau das zu sein was ich gesucht habe.



  • (mit windows) geht auch:

    #include <ppl.h>
    
    using namespace concurrency;
    
    ...
    


  • manni66 schrieb:

    Threads in einer parallel_for-Funktion zu starten und wieder zu beenden ist wohl nicht wirklich sinnvoll. Threads sind teuer.

    +1
    Man sollte vielleicht dazusagen: Threads erzeugen bzw. joinen ist teuer. Threads grundsätzlich sind nicht teuer 🤡

    @wolfsberger
    Also...

    while (position < end)
            {
                positionMutex.lock();
                int number = position;
                position++;
                positionMutex.unlock();
    
                func(number);
            }
    
    • while (position < end) ist ne Race-Condition, da nicht synchronisiert
      * Lock+Unlock einer Mutex pro Schleifendurchlauf wäre für kurze "func" sehr schlecht, würde massiv Performance kosten

    Besser ist es den einzelnen Threads Blöcke von zusammenhängenden Nummern zuzuweisen. Der Trick dabei ist es hinzubekommen dass man keinem Thread zu viel gibt. Weil ja nicht jeder Aufruf von func() gleich lange dauern wird. Man denke bloss man an Apfelmännchen Zeichnen.



  • BTW, deine schleifen laufen nur bis Maxthreads. Da muesste dann noch eine schleife drum, die bis end laeuft.



  • Ja, die Threads-Erzeuge und Threads-Joine-Schleifen sollen ja auch nur bis MaxThreads laufen.
    Guggstdu in Lambda das while (position < end) wenn du die andere Schleife suchst.



  • Stimmt. Me <- blind



  • Welcome to the club 🕶


  • Mod

    hustbaer schrieb:

    Welcome to the club 🕶

    Lol 😃 😃


Log in to reply