2016-07-02 3 views
2

Ich versuche große Anzahl von Dateien aus verschiedenen Verzeichnissen auf unterschiedlichen Hosts zu einem einzigen Verzeichnis zu kopieren. Da es sich als ziemlich zeitaufwändig herausstellte und ich dieses Programm mehrmals ausführen musste, änderte ich den Code, um die Hilfe von Multithread zu nutzen, wobei jeder Thread XCOPY durch einen Prozess ausführt.Fehlende Dateieinträge, wenn mehrere Threads generierten Prozesse Dateien in demselben Verzeichnis C# kopieren

Allerdings fand ich heraus, dass, wenn ich Multi-Thread Kopieren tue, einige Dateien (weniger als 100, variiert jedes Mal) nicht kopiert zu werden. Ich habe nicht gedacht, ob es wegen mehrerer Prozesse ist gegenseitig dazwischen, wenn im selben Verzeichnis XCOPYing, oder es ist eher ein XCOPY Problem (nicht sicher, wie gut es Multi-Prozess auf demselben Ziel unterstützt Aufruf).

List<Thread> threadList = new List<Thread>; 

foreach(FileEntry fileEntry in fileEntries) 
{ 
    Thread thread = new Thread(() => { 
     //full path of file, like \\host\directory\directoryB\fileA.txt 
     string filePath = fileEntry._filePath; 

     //name of file, like fileA.txt 
     string file = fileEntry._file; 

     //dumpDirectory is where I want to copy all the files to 
     string destPath = Path.Combine(dumpDirectory, file); 

     //each file here is either a directory or a real file, bad naming convention I know...(open to suggestions if any) 
     string fileType = File.Exists(filePath) ? "f" : "d"; 

     using (Process process = new Process()) 
     { 
      process.StartInfo.CreateNoWindow = true; 
      process.StartInfo.UseShellExecute = false; 
      process.StartInfo.FileName = "cmd.exe"; 

      process.StartInfo.Arguments = string.Format(@"/C echo {0} | XCOPY /E /C /H /R /K /O /Y {1} {2}", fileType, filePath, destPath); 

      Console.WriteLine("copying {2} [{0}] to destination [{1}]", filePath, destPath, string.Compare(fileType, "f") == 0 ? "file" : "directory"); 
      process.Start(); 
      process.WaitForExit(); 

      if (process.ExitCode != 0) 
      { 
       Console.WriteLine("encountered problems when copying file [{0}]", filePath); 
      } 
     } 
    }); 

    thread.Start(); 
    threadList.Add(thread); 
} 

foreach(Thread thread in threadList) 
{ 
    thread.Join(); 
} 

--------------------------- Fehlerbehebung wie folgt ------------ -------------------

so von Antworten unten vorgeschlagen, wie (danke Jungs für die schnellen Antworten, sparte mein Wochenende^_ ^), habe ich den Prozess-Ausgang umgeleitet und festgestellt, dass das Problem ist "Sharing violation \ n Kann Verzeichnis nicht erstellen". xcopy hat Probleme, wenn mehrere Dateien in dasselbe Verzeichnis kopiert werden (verschiedene xcopy-Prozesse scheinen zur gleichen Zeit ein Verzeichnis zu erstellen, wenn alle feststellen, dass das Verzeichnis auf dem System nicht existiert).

Ändern das manuelle Thread-Management zu Parallel.ForEach das Problem gelöst und machte den Code schöner aussehen (obwohl ich nicht herausgefunden habe, warum es nicht das gleiche Problem zu schaffen)

Oder ein dreckiges fix ist zu wickeln up.process.Start() mit einem EventWaitHandle. Ich Instanzen verschiedene Eventwaithandle basiert eher auf dem Zielverzeichnis verwendet als mit einem Handgriff, weil der andere Weg, um den Zweck der Verwendung von Multi-Prozess-

//name the wait handle based on destination value 
EventWaitHandle destWaitHandle = new EventWaitHandle(true, EventResetMode.AutoReset, string.Format("waitHandle{0}", destPath.GetHashCode())); 

//only trigger the wait handle lock if the file being copied from (and to) is a directory. Based on the error log info XCopy seemed to never have issues with copying individual files 
//and the program worked fine if I only put the lock at directory level 
if (string.Compare(fileType, "d") == 0) 
{ 
    destWaitHandle.WaitOne(); 
} 

process.Start(); 

//this line was added to write error messages into respective files during the process' execution 
process.BeginErrorReadLine(); 
process.WaitForExit(); 

if (string.Compare(fileType, "d") == 0) 
{ 
    destWaitHandle.Set(); 
} 
+0

Vielleicht haben Sie Ihre StandardOutput von Process.Start zeigen konnte ... Etwas geschieht es –

+0

I d Ich weiß nicht, wie ich direkt auf den obigen Kommentar antworten kann, aber ich möchte dir einfach [x ...] für die Hilfe danken. Wie vorgeschlagen, habe ich die gesamte Ausgabe umgeleitet/gelöscht und herausgefunden, wo das Problem lag. –

+0

Es ist sehr wenig sinnvoll, Multi-Threading zum Kopieren von Dateien zu verwenden. Threads sind vorteilhaft, wenn Sie über CPU-gebundene Operationen verfügen. Bei IO ist die CPU praktisch leer. In der Tat kann das Multithreading-IO ** das Kopieren ** verlangsamen **, da Sie Festplattenkonflikte einführen und ** beim Kopiervorgang ** Fehler verursachen können. – Enigmativity

Antwort

0

Zunächst einmal besiegen wird, schlage ich Sie auf die Aufgabenorientierte Code wechseln , da die Erstellung von Threads in einer solchen Anzahl aufgrund der Kontextwechsel zu einem Downgrade der Performance führen kann.

Sie können ganz einfach dies mit Parallel-Erweiterungen, wie folgt aus:

Parallel.ForEach(fileEntries, fileEntry => { // YOUR code here }; 

Zweitens können Sie untersuchen die Fehler ist aufgetreten im XCOPY Prozess durch Examing die StandardError Eigenschaft des Process Objekt, wie @x .. . vorgeschlagen, something like this (Sie können es auch auf die Fähigkeit, sie umleiten müssen lesen):

process.StartInfo.RedirectStandardError = true; 
// ... 
if (process.ExitCode != 0) 
{ 
    Console.WriteLine("encountered problems when copying file [{0}]", filePath); 
    Console.WriteLine(process.StandardError.ReadToEnd()); 
} 
+0

Vielen Dank. Ich warf die Nachrichten in eine Datei und fand heraus, wo das Problem lag. In der Fehlerspeicherdatei heißt es "Freigabeverletzung \ n Kann Verzeichnis nicht erstellen". Ich wickelte die process.Start() mit einem waitHandle (im Wesentlichen eine Inter-Prozess-Level-Sperre) basierend auf dem Hash-Wert des Zielverzeichnisses, und die Dateien werden alle korrekt kopiert. Der Parallel.Foreach ist definitiv eine bevorzugte Methode. Ich habe es zuerst versucht, ohne das waitHandle zu benutzen und das Programm hat gut funktioniert (obwohl ich nicht herausgefunden habe, warum es nicht in die gleichen Schwierigkeiten geriet). –

+0

@ T.L. Ich denke, dass das Problem durch den 'Parallel'-Ansatz gelöst wurde, da es nur eine bestimmte Anzahl von Threads in einem Moment startet, so dass das Rennen nicht stattfinden wird. – VMAtm

Verwandte Themen