Threads werden nicht parallel auf der CPU ausgeführt?



  • Hallo Forum,
    kann das überhaupt sein?
    Ich habe folgendes Problem mein Anwendung lief sequenziell folgende Funktionen ab:
    eine DateiSuche();
    und im Anschluss wurden die gefundenen DateienVerarbeiteten();
    Da die Suche mit unter sehr lange dauerte habe ich diese Funktion in einen eigenen Thread gepackt und gleich einen Thread gestartet, der die Dateien die schon gefundenen wurden Dateien verarbeitet.
    Ich hab an meinem Rechner 4 Kerne , da dachte ich mir da können ja auch 4 Threads laufen die die anfallenden Daten verarbeiten. Jetzt ist mir aber aufgefallen das die CPU-Last bei 3 Threads nicht wirklich steigt, mein Prozessor bleibt bei 25% Auslastung. Jetzt vermute ich, dass die Threads zwar alle laufen aber sich wahrscheinlich gegenseitig so locken, dass sie in Endeffekt doch sequenziell ablaufen. Ein wirklichen Geschwindigkeitsvorteil bekomme ich nämlich nicht,egal ob ich mit 1 oder 4 Threads die Daten verarbeite es dauert immer gleich lang. Irgendwas scheine ich falsch zu machen was könnte das sein? Hier der Code wie ich es in etwa umgesetzt habe:

    [cs]
    class Main
    {
    Thread mSearchThread;
    List<System.IO.FileInfo> mFoundedFiles;
    List<string> mAllFoundedFiles;
    bool mSearching = false;
    
    public void StartThreads()
    {
     SearchClass mSearch = new SearchClass();
     SearchClass.FoundNewFile +=  new SearchClass.FindNewFileEventHandler  (SearchClass_FindNewFile);
      SearchClass.EndSearch += new EventHandler(OnFileSearchComplete);
     mSearching = true;
     mSearchThread =
                    new Thread(new ThreadStart(SearchClass.SearchFiles));
     mSearchThread.Start();
    
     List<Thread> tThreads = new List<Thread>(8);
     Thread tCurrentThread;
     ThreadStart tThreadStart = null;
     for (int i = 0; i < 4; i++)
     {
       tCurrentThread = new Thread(new ThreadStart(ProcessingFilesForThread));
       tCurrentThread.Priority = ThreadPriority.Normal;
       tCurrentThread.Name = "Name:" + i.ToString();
       tThreads.Add(tCurrentThread);
      }   
      foreach (Thread th in tThreads)
       th.Start();
      foreach (Thread th in tThreads)
       th.Join();
    }
    
    private SearchClass_FindNewFile(object pSender, MyFileSearchArgs pFileInfo)
    {
     lock(mFoundedFiles)
     { 
      mFoundedFiles.Add(pFileInfo.FileInfoObj);
      mAllFoundedFiles.Add(pFileInfo.FileName);
      Monitor.Pulse(mFoundedFiles);
     }
    }
    
    private OnFileSearchComplete(object sender, EventArgs e)
    {
     lock(this)
      {
       mSearching = false;
      }
    }
    
    private void ProcessingFilesForThread()
    {
     MyFoundedFileInfo tFile = GetNextFoundedFile();
      while(tFile  != null || mSearching)
       {        
         //MacheWas
        tFile = getNextFoundedFile();
       }
    }
    
    private MyFoundedFileInfo GetNextFoundedFile()
    {
     MyFoundedFileInfo tFileInfo =null;
     lock (mFoundedFiles)
     {
      if(mFoundedFiles.Count == 0 && mSearching)
      {
       Monitor.Wait (mFoundedFiles);  
      }
      if(mFoundedFiles.Count > 0)
      {          
         tFileInfo = new MyFoundedFileInfo(mFoundedFiles[0],mFileRun++);          
         mFoundedFiles.RemoveAt(0);         
      }     
     }
     return tFileInfo;
    }
    }[/cs]
    

    DeadLock hatte ich bis jetzt noch keine 😉 und abgearbeitet werden auch alle nur leider Sequenziell ....
    Viele Grüß



  • Ich habe deinen Code nicht im Detail angeschaut aber es sieht tatsächlich danach aus, als würde wegen den vielen locks alles sequenziell abgearbeitet.

    Ich könnte mir vorstellen, dass folgender Ansatz zimelich gut klappen könnte:
    - Gib deiner Klasse eine (thread-safe) Queue, die gefundene Dateien speichert, die du weiterverarbeiten musst.
    - Starte einen Thread, der permanent Daten sucht und, falls er eine entsprechende Datei gefunden hat, diese Datei in der Queue speichert.
    - Starte mehrere Threads, die folgendes tun: Sie nehmen eine zu verarbeitende Datei aus der Queue (und entfernen sie aus der Queue) und verarbeiten die Datei.

    Der Vorteil von diesem Ansatz ist, dass sobald ein Thread einmal eine Datei (aus der Queue) hat, kann er vollkommen unabhänig rechnen, d.h. es kann wirklich parallel gerechnet werden.

    Zu beachten:
    - Wenn der Rechenaufwand pro Verarbeitung einer Datei sehr klein ist, dann kann durch Overhead, der durch die Parallelisierung entsteht, die Performance schlechter werden. Auch wird dann wohl das Lesen der Dateien ein Bottleneck sein.
    - Mehrere Threads zu starten, die nach Dateien suchen, dürfte nicht sinnvoll sein. HDs sind sehr schlecht darin an verschiedenen Orten zu lesen, da es für den Lesekopf lange dauert sich an eine gewisse Position zu bewegen. Ist der Lesekopf allerdings einmal an der korrekten Position kann ziemlich schnell gelesen werden. Deswegen solltest du so lokal wie möglich lesen, d.h. nur ein Thread, der liest.



  • Hi,
    danke für die schnelle Antwort,ich werde es mal versuchen auf eine Queue umzubauen, obwohl es sich schon sehr ähnlich anhört was du da beschreibst und was ich mache. Ich locke die Liste im Prinzip ja auch nur beim lesen und schreiben.

    "Such-Threads " hatte ich ja auch nur einen, da mir schon klar war das der Lesekopf bei mehren Threads nur hin und her springt und das wahrscheinlich Zeit kostet. Was ich mich aber nun in diesen Zusammenhang frage ist, wie sich das bei modernen SSD Platten verhält? Da gibts ja soviel ich weiß keinen Lesekopf mehr.
    Grüße



  • DrBo1982 schrieb:

    Was ich mich aber nun in diesen Zusammenhang frage ist, wie sich das bei modernen SSD Platten verhält? Da gibts ja soviel ich weiß keinen Lesekopf mehr.

    SSD haben keine "Platten", SSDs sind im wesentlichen eine Art Flashspeicher (entfernt mit einem USB-Stick zu vergleichen).


Anmelden zum Antworten