pthread Ergebnisse verstehen



  • Hallo,

    ich spiel gerade etwas mit pthreads herum. Dabei hab ich ein Programm geschrieben, dass parallel und sequenziell die Zahlen von 1 bis n addiert, in beiden Fällen kommt wie erwartet n(n+1)/2 raus.
    Was mich aber überrascht sind die Laufzeiten, ich hab hier einen amd64 Linux Rechner mit Quadcore:

    ~/dev/pthreadsfun$ ./a.out 5 500000000
    workers: 5
    numbers: 500000000
    parallel result: 125000000250000000
    parallel time: 0.4
    single result: 125000000250000000
    single time: 0.26

    ~/dev/pthreadsfun$ ./a.out 50 500000000
    workers: 50
    numbers: 500000000
    parallel result: 125000000250000000
    parallel time: 0
    single result: 125000000250000000
    single time: 0.26

    Sprich das Ausführen mit 5 Workern ist zum einen langsamer, als das sequentielle Ausführen. Das könnte ich ja durch den Mehraufwand des Erstellen der Threads und der worker_structs etc. noch verstehen, auch wenn ich erwartet hätte, dass sich das bei 5e8 Additionen bereits relativiert.
    Aber warum wird das Programm mit 50 Workern (bei 40 braucht es noch 0.1) schneller als mit 5? Der Overhead wird noch viel größer, und ich hab doch ohnehin nur 4Kerne. Auch bei 500 Workern wird als Zeit noch '0' ausgegeben.

    Würd mich über Antworten freuen. 🙂

    #include <pthread.h>
    #include <iostream>
    
    #include <time.h>
    #include <stdlib.h>
    
    struct worker_struct{
      int from;
      int to;
    };
    
    void* worker(void* p){
      worker_struct data = *((worker_struct*)p);
      long* result = new long;
      *result = 0;
      for(long i=data.from; i<=data.to; i++)
        *result += i;
      return result;
    }
    
    long single_sum(long n_numbers){
      long result = 0;
      for(long i=1; i<=n_numbers; i++)
        result += i;
      return result;
    }
    
    long parallel_sum(int n_worker, int n_numbers){
      pthread_t worker_thread[n_worker];
      worker_struct data[n_worker];
    
      for(long i=0; i<n_worker; i++){
        data[i].from = i*n_numbers/n_worker+1;
        data[i].to = (i+1)*n_numbers/n_worker;
        pthread_create(&worker_thread[i],0,worker,&data[i]);
      }
    
      long result = 0;
      long* worker_result = new long;
      for(int i=0; i<n_worker; i++){
        pthread_join(worker_thread[i],(void**)&worker_result);
        result += *(worker_result);
      }
    
      return result;
    }
    
    int main(int argc, char** argv){
      if(argc < 3){
         std::cout << "Number of threads and numbers to add?" << std::endl;
         return 1;
      }
      int n_worker = atoi(argv[1]);
      long n_numbers = atoi(argv[2]);
      std::cout << "workers: " << n_worker << std::endl;
      std::cout << "numbers: " << n_numbers << std::endl;
    
      clock_t begin;
      clock_t end;
      begin = clock();
      long result = parallel_sum(n_worker, n_numbers);
      end = clock();
      std::cout << "parallel result: " << result << std::endl;
      std::cout << "parallel time: " << (double)(end-begin)/CLOCKS_PER_SEC << std::endl;
    
      begin = clock();
      result = single_sum(n_numbers);
      end = clock();
      std::cout << "single result: " << result << std::endl;
      std::cout << "single time: " << (double)(end-begin)/CLOCKS_PER_SEC << std::endl;
    
      return 0;
    }
    

    P.S. Ich weiß, dass man es durch zyklische Reduktion noch optimieren kann, aber ich wollte es erst einmal simpel halten. 😉



  • Du hast einen schlechten Benchmark. Auch weisst du nicht, wie andere Prozesse im Hintergrund gerade zuschlagen. Der Einfluss kann sehr hoch sein, bei solch geringer Laufzeit. Deine Ergebnisse sind nicht aussagekraeftig. Ich haette auch gettimeofday fuer die Zeitmessung benutzt.



  • Aber der Einfluss anderer Prozesse wird doch nichts daran ändern, dass bei weit aus mehr Workern als Cores das Ergebniss besser ist, als bei #Worker = #Cores+1.
    Zumindest kann ich das Programm ausführen so oft ich will und daran ändert sich nichts.
    Werd mal ein paar andere sinnlose Rechnereien ausprobieren die länger dauern und auch gettimeofday verwenden.



  • Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung in das Forum Linux/Unix verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • die auflösung deiner clock() ist vermutlich viel zu schlecht, als dass du da irgendwas sinnvolles rausbekommen würdest.

    weiters solltest du vermutlich etwas ein wenig aufwendigeres in dem thread berechnen.

    und für einen fairen test, solltest du auch für beide varianten exakt die gleiche schleife verwenden. nicht einmal über struct und zeiger, und einmal direkt über variablen/konstanten.

    d.h.: ruf einfach die worker() funktion mit werten für nur einen thread auf.



  • benutze eine andere timer funktion

    clock() zählt die clock-ticks in jedem zusätzlichen thread einfach dazu


Anmelden zum Antworten