c# - 文件传输占用大量 CPU

标签 c# asp.net .net web-services ihttphandler

我正在尝试通过 IHttpHandler 传输文件,代码非常简单。然而,当我开始单次传输时,它使用了大约 20% 的 CPU。如果我将其扩展到 20 个同时传输,则 CPU 非常高。有没有更好的方法可以降低 CPU 占用率?客户端代码一次只发送 64KB 的文件 block 。

public void ProcessRequest(HttpContext context)
{
      if (context.Request.Params["secretKey"] == null)
      {

      }
      else
      {
           accessCode = context.Request.Params["secretKey"].ToString();
      }

      if (accessCode == "test")
      {
           string fileName = context.Request.Params["fileName"].ToString();
           byte[] buffer = Convert.FromBase64String(context.Request.Form["data"]);
           string fileGuid = context.Request.Params["smGuid"].ToString();
           string user = context.Request.Params["user"].ToString();

           SaveFile(fileName, buffer, user);
      }
}

public void SaveFile(string fileName, byte[] buffer, string user)
{
      string DirPath = @"E:\Filestorage\" + user + @"\";

      if (!Directory.Exists(DirPath))
      {
          Directory.CreateDirectory(DirPath);
      }

      string FilePath = @"E:\Filestorage\" + user + @"\" + fileName;
      FileStream writer = new FileStream(FilePath, File.Exists(FilePath) ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
      writer.Write(buffer, 0, buffer.Length);
      writer.Close();
}

这是我的客户端代码:

//Set filename from object
                string FileName;
                FileName = System.IO.Path.GetFileName(pubAttFullPath.ToString());

                //Open file
                string file = System.IO.Path.GetFileName(pubAttFullPath.ToString());
                FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                //Chunk size that will be sent to Server
                int chunkSize = 65536;
                // Unique file name
                string fileName = smGuid.ToString() + "_" + FileName;
                int totalChunks = (int)Math.Ceiling((double)fileStream.Length / chunkSize);
                // Loop through the whole stream and send it chunk by chunk;
                for (int i = 0; i < totalChunks; i++)
                {
                    bool doRecieve = true;
                    int cpt = 0;
                    do
                    {
                        int startIndex = i * chunkSize;
                        int endIndex = (int)(startIndex + chunkSize > fileStream.Length ? fileStream.Length : startIndex + chunkSize);
                        int length = endIndex - startIndex;

                        byte[] bytes = new byte[length];
                        fileStream.Read(bytes, 0, bytes.Length);


                        //Request url, Method=post Length and data.
                        string requestURL = "http://localhost:16935/Transfer.doit";
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
                        // Wait 5 min for answer before close connection.
                        request.Timeout = 300000;
                        request.Method = "POST";
                        request.ContentType = "application/x-www-form-urlencoded";

                        // Chunk(buffer) is converted to Base64 string that will be convert to Bytes on  the handler.
                        string requestParameters = @"fileName=" + fileName + @"&secretKey=test" + @"&currentChunk=" + i + @"&totalChunks=" + totalChunks + @"&smGuid=" + smGuid 
                        + "&user=" + userSID.ToString() +
                        "&data=" +  HttpUtility.UrlEncode(Convert.ToBase64String(bytes));

                        // finally whole request will be converted to bytes that will be transferred to HttpHandler
                        byte[] byteData = Encoding.UTF8.GetBytes(requestParameters);

                        request.ContentLength = byteData.Length;
                        try
                        {
                            Stream writer = request.GetRequestStream();
                            writer.Write(byteData, 0, byteData.Length);
                            writer.Close();
                            // here we will receive the response from HttpHandler
                            StreamReader stIn = new StreamReader(request.GetResponse().GetResponseStream());
                            string strResponse = stIn.ReadToEnd();
                            stIn.Close();
                            doRecieve = true;
                        }
                        catch (WebException webException)
                        {
                            if (webException.Status == WebExceptionStatus.ConnectFailure ||
                                webException.Status == WebExceptionStatus.ConnectionClosed ||
                                webException.Status == WebExceptionStatus.ReceiveFailure ||
                                webException.Status == WebExceptionStatus.SendFailure ||
                                webException.Status == WebExceptionStatus.Timeout)
                            {
                                Thread.Sleep(5000);
                                doRecieve = false;
                                cpt++;
                            }
                            else {
                                // if the exception is not those ones then get out
                                doRecieve = true;
                            }
                        }
                        catch (Exception e)
                        {
                            doRecieve = true;
                        }
                    }
                    // will try to send 3 times the current chunk before quitting
                    // can't try it so try it and give me the feedback
                    while(doRecieve == false && cpt < 3);
                 }

最佳答案

我没有测试过这个理论,但使用 FromBase64String 可能是原因。我找到了 this case有人使用此方法耗尽了内存。

你可以试试 FromBase64Transform相反,它旨在处理数据流。


或者如果您出于任何原因不需要使用 base64,请查看 this solution from Scott Hanselman .

关于c# - 文件传输占用大量 CPU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11090689/

相关文章:

javascript - 检查 AngularJS 模块是否被引导

asp.net - 共享 .NET 应用程序池

c# - 错误 CS5001 : exe does not contain a static `Main' method suitable for an entry point

c# - 创建没有委托(delegate)的线程 - 为什么这有效?

javascript - 如何获取li ul内的span动态值

c# - 如何从 wpf 中的文本框聚焦光标?

c# - 通过什么 .NET 类来代理 HTTP 请求? (并跟踪使用的带宽)

c# - Entity Framework 代码首次迁移 : get sql scripts programmatically

c# - 当我们指定了类的访问说明符时,是否有任何约束来指定类成员的访问说明符?

单个 MongoDB 实例上的 C# MongoDB 驱动程序事务