2016-09-21 7 views
1

Ich verwende Librsync in einem Projekt, um die Unterschiede zwischen zwei Versionen einer Datei zu berechnen und die Änderungen auf die alte Datei anzuwenden.Stream.CopyTo hängt bei Verwendung mit Librsync.PatchStream

Außerhalb meines Projekts habe ich es in einer einfachen Konsole App funktioniert, die die Dateien aus 2 verschiedenen Verzeichnissen liest, "Patches" sie und schreibt es in ein gepatchtes Verzeichnis.

Codebeispiel -

using (var deltaFile = new FileStream(tmpDeltaFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) 
{ 
    //myClient is the client of a WCF service I created 
    myClient.ComputeDelta(file.Id, signatureStream).CopyTo(deltaFile); 

    originalFile.Seek(0, SeekOrigin.Begin); 
    deltaFile.Seek(0, SeekOrigin.Begin); 
    var patchedStream = Librsync.ApplyDelta(originalFile, deltaFile); 

    using (var patchedFileStream = new FileStream(patchedFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) 
    { 
     //Code below just hangs. patchedStream pos = 0 and the length is the same as that of the new file. 
     patchedStream.CopyTo(patchedFileStream); 
    } 
} 
+0

Pausieren Sie den Debugger und buchen Sie den Call-Stack der Hand mit externem Code. – usr

+0

Hangs auf - 'public override int Read (byte [] buffer, int offset, int count) { return ReadAsync (Puffer, Offset, count) .RESULT; } ' in PatchedStream.cs https://github.com/braddodson/librsync.net/blob/master/librsync.net/PatchedStream.cs – chickenbeef

+0

Die' .Result' Ding sieht aus wie eine klassische ASP. NET Deadlock. Es ist ein Fehler in unbekanntem Code. Wickle das Ganze in 'Task.Run (() => ...). Wait();' um das zu testen. – usr

Antwort

1

In den Kommentaren fanden wir heraus, dass es sich um eine Instanz des "klassischen ASP.NET Deadlock".

Im Idealfall finden Sie den Ort, an dem Sie await verwenden und ConfigureAwait(false) fehlen.

Ich glaube nicht, dass dies ein Fehler in der Rsync-Bibliothek ist. Das Anrufen von Result für eine Aufgabe ist nicht verboten, wenn die Umstände es erfordern. Die Bibliothek darf davon ausgehen, dass dies nicht zum Stillstand kommt. Es gibt keine Möglichkeit zu überprüfen, ob dies eine sichere Operation ist, also muss es nur tun und sich auf Anrufer verlassen, um korrekte Objekte bereitzustellen.

Eine schnelle Lösung besteht darin, den Rsync-Code in Task.Run(() => ...).Wait(); zu verpacken, wodurch der Synchronisationskontext für die Dauer dieses Codes effektiv gelöscht wird. Dadurch hat der fehlende ConfigureAwait(false) keinen Einfluss mehr.

Dieser Fix ist normalerweise akzeptabel. Es verursacht Leistungseinbußen, da es einen weiteren Thread verbraucht und einige Synchronisierungskosten verursacht. Normalerweise ist dies belanglos. Wenn Sie eine zufällige ASP.NET-App verwenden und die Anzahl der Threads verdoppeln, ist die Wahrscheinlichkeit hoch, dass dies fast null Auswirkungen hat. Auf der Oberseite ist der Fix eindeutig korrekt und leicht zu pflegen.

Verwandte Themen