2016-09-21 48 views
1

我在项目中使用Librsync来计算文件的两个版本之间的差异并将更改应用于旧文件。Stream.CopyTo与Librsync.PatchStream一起使用时挂起

在我的项目之外,我在一个简单的控制台应用程序中工作,该应用程序从2个不同的目录中读取文件,“修补”它们并将其写入补丁目录。

代码示例 -

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

暂停调试器并用外部代码发布手的调用堆栈。 – usr

+0

挂起 - 'public override int Read(byte [] buffer,int offset,int count) { return ReadAsync(buffer,offset,count).Result; }' 在PatchedStream.cs https://github.com/braddodson/librsync.net/blob/master/librsync.net/PatchedStream.cs – chickenbeef

+0

的'.Result'东西看起来像一个传统的ASP。 NET死锁。这是一个未知代码中的错误。把整个东西包装在'Task.Run(()=> ...)。Wait();'来测试这个。 – usr

回答

1

在评论中,我们发现,这是“经典ASP.NET僵局”的一个实例。

理想情况下,你会发现你使用的地方await和缺少ConfigureAwait(false)

我不认为这是Rsync库中的一个错误。如果情况需要,在任务上调用Result不会被禁止。图书馆可以认为这不会造成死锁。它无法检查这是否是安全操作,因此它必须执行此操作并依靠呼叫者提供正确的对象。

快速解决方法是将Rsync代码包装在Task.Run(() => ...).Wait();中,该代码在此代码持续时间内有效清除同步上下文。因为缺少的ConfigureAwait(false)已经不再有影响了。

此修复通常是可以接受的。它具有性能成本,因为它消耗了一个线程并且有一些同步成本。通常情况下,这是无关紧要的。如果你使用一个随机的ASP.NET应用程序并把线程数加倍,那么这个机会几乎没有影响。在优势方面,修复显然是正确的,易于维护。