2009-08-14 78 views
0

我正在使用.NET编写一个简单的Web服务,一种方法是用来从客户端向服务器发送一个文件块,服务器打开一个临时文件并追加这个块。这些文件非常大,80Mb,网络IO似乎很好,但随着文件变大,附加写入本地文件的速度逐渐减慢。文件IO缓慢或缓存在Web服务中?

后续是减慢,服务器,å文件是一个字符串上运行的代码,ADATA是一个byte []

 using (StreamWriter lStream = new StreamWriter(aFile, true)) 
     { 
      BinaryWriter lWriter = new BinaryWriter(lStream.BaseStream); 
      lWriter.Write(aData); 
     } 

调试这个过程中,我可以看到,在离开using语句是越来越慢。

如果我运行在一个简单的独立测试应用程序的代码的写操作每次都以相同的速度约3毫秒,请注意缓冲液(ADATA)总是相同的侧上,约0.5兆。

我已经尝试了各种不同的作家的实验,系统副本追加临时文件,所有在Web服务下运行时都放慢速度。

这是怎么发生的?我怀疑Web服务试图缓存对本地文件系统对象的访问权限,我如何关闭特定文件?

更多信息 -

如果我硬编码路径的速度是好的,像这样

 using (StreamWriter lStream = new StreamWriter("c:\\test.dat", true)) 
     { 
      BinaryWriter lWriter = new BinaryWriter(lStream.BaseStream); 
      lWriter.Write(aData); 
     } 

但随后缓慢复制这个临时文件的最终文件目的地以后 -

 File.Copy("c:\\test.dat", aFile); 

如果我在路径中使用任何varibale,它会变慢,例如 -

 using (StreamWriter lStream = new StreamWriter("c:\\test" + someVariable, true)) 
     { 
      BinaryWriter lWriter = new BinaryWriter(lStream.BaseStream); 
      lWriter.Write(aData); 
     } 

已经评论说,我不应该使用的StreamWriter,请注意我尝试使用的FileStream,其中没有当代码的Web服务下运行所做的任何改变许多方法来打开该文件,我想一直写等

它我甚至试过这种奇怪的事情 -

Write the data to file a.dat 
Spawn system "cmd" "copy /b b.dat + a.dat b.dat" 
Delete a.dat 

这会减慢一样????

使我认为Web服务器运行在一些受保护的文件IO环境中捕获此过程和子进程中的所有文件操作,如果我生成的文件可能稍后会提供给客户端,我可以理解这一点,但是我我没有,我正在做的是在磁盘上存储大的二进制blob,并在索引/指针存储在数据库中,如果我注释写入文件,整个过程根本没有性能问题。

我开始阅读关于Web服务器缓存策略,让我觉得有一个web.config设置标记为未缓存的文件夹?或者我完全吠叫错了树。

+0

你在什么下运行web服务? cassini或IIS?您的测试客户端是否使用相同路径与web服务在同一个系统上运行? – 2009-08-14 02:12:38

+0

从VisualStudio运行,最终它将从卡西尼运行。我已经尝试在系统临时目录中找到临时文件,并在Web服务根目录下找到一个文件夹,无论如何,无论如何,都会发生同样的减速,看起来Web服务正在高速缓存对文件的访问。 – titanae 2009-08-14 02:50:02

+0

我并不建议你停止使用'StreamWriter'作为性能改进。我建议这样做,因为如果你正在编写二进制数据,使用它就毫无意义。由于'BinaryWriter'已经在使用'BaseStream',所以性能不会提高。 – 2009-08-14 11:33:22

回答

0

那么我发现根本原因,“微软Forefront安全”,组策略有这个运行实时扫描,我可以看到当我关闭该文件时,该进程得到30%的CPU使用率,杀死这个过程,一切工作相同速度,外部和内部的网络服务!

下一个任务找到一种方法来添加一个排除MFS!

0

远景:完成后是否需要关闭一些资源?

+0

我不这么认为,在我看来,当文件关闭时,Web服务器进程正在将整个文件读入缓存。 – titanae 2009-08-14 11:36:54

0

如果文件是二进制文件,那么为什么使用从TextWriter派生的StreamWriter?只需使用FileStream即可。

此外,BinaryWriter实现IDisposable,你需要把它放入一个使用块。

+0

是/否,因为StreamWriter打开文件,它关闭它,我试图显式调用close,并且使用FileStream打开文件,它们没有任何作用,当StreamWriter被处理时是当我看到缓慢的时候,追加,20毫秒下一次等,当文件超过10Mb它变得真的很慢,超过2秒。 – titanae 2009-08-14 11:32:08

0

更新....我复制的基本代码,没有数据库,简单,它似乎好工作,所以我怀疑还有另外一个原因,我将休息上周末....

这里是复制的服务器代码 -

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Services; 
using System.IO; 
namespace TestWS 
{ 
/// <summary> 
/// Summary description for Service1 
/// </summary> 
[WebService(Namespace = "http://tempuri.org/")] 
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
[System.ComponentModel.ToolboxItem(false)] 
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService] 
public class Service1 : System.Web.Services.WebService 
{ 

    private string GetFileName() 
    { 
     if (File.Exists("index.dat")) 
     { 
      using (StreamReader lReader = new StreamReader("index.dat")) 
      { 
       return lReader.ReadLine(); 
      } 
     } 
     else 
     { 
      using (StreamWriter lWriter = new StreamWriter("index.dat")) 
      { 
       string lFileName = Path.GetRandomFileName(); 
       lWriter.Write(lFileName); 
       return lFileName; 
      } 
     } 
    } 

    [WebMethod] 
    public string WriteChunk(byte[] aData) 
    { 
     Directory.SetCurrentDirectory(Server.MapPath("Data")); 
     DateTime lStart = DateTime.Now; 
     using (FileStream lStream = new FileStream(GetFileName(), FileMode.Append)) 
     { 
      BinaryWriter lWriter = new BinaryWriter(lStream); 
      lWriter.Write(aData); 
     } 
     DateTime lEnd = DateTime.Now; 
     return lEnd.Subtract(lStart).TotalMilliseconds.ToString(); 
    } 
} 

}

而且复制的客户端代码 -

static void Main(string[] args) 
    { 
     Service1 s = new Service1(); 
     byte[] b = new byte[1024 * 512]; 
     for (int i = 0 ; i < 160 ; i ++) 
     { 
      Console.WriteLine(s.WriteChunk(b)); 
     } 
    } 
+0

我认为它可能是VisualStudio,在调试器中运行客户端,并且分离的Web服务似乎很快,运行速度相反,调试Web服务,客户端分离也很慢!这是有道理的,VisualStudio试图拦截一切...还没有确信。 – titanae 2009-08-14 12:44:37

0

根据您的代码,它显示您正在使用StreamWriter内部的文件默认处理,这意味着文件上的同步和排它锁定。

根据你的意见,你真正想解决的问题是从Web服务返回的时间 - 不一定是文件的写入时间。虽然写入时间是您发现的当前门控因子,但您可以通过进入异步写入模式来解决问题。

或者,我更喜欢完全分离的异步操作。在这种情况下,数据的入站字节[]将被保存到它自己的文件(或其他结构)中,然后通过辅助进程附加到主文件中。操作更复杂,但也更不容易发生故障。

+0

我开始认为它可能是GC的工作,因为当文件上传多个其他客户端在服务器触发请求涉及数据提取,我想我可能需要更加宽松地使用“使用”语句?我会在下周发现。 – titanae 2009-08-15 03:37:04

0

我没有足够的积分来回答问题,但是jro有正确的想法。我们在我们的服务中做类似的事情;每个块都保存到一个临时文件中,然后一旦收到所有块,它们就会重新组合成一个文件。

我不确定使用StreamWriter将数据附加到文件的底层进程,但我会假设在尝试将任何内容写入缓冲区之前它至少必须读取到当前文件的末尾它。所以随着文件变大,在编写下一个块之前,必须读取越来越多的现有文件。

+0

可能,但情景是客户端上传必须存储在文件中的数据,一旦完成客户端将要求服务器对数据执行操作,服务器通过启动服务器上的外部进程来处理数据在文件中。我可以将写入写入文件,但最终客户端将不得不与服务器同步,客户端完成上载,服务器确认接收文件,客户端指示服务器处理文件,它们可能会在稍后的部分延迟客户端可以上传多个文件。 – titanae 2009-08-15 03:34:53