【问题标题】:Why does my async action hang while downloading large files?为什么我的异步操作在下载大文件时挂起?
【发布时间】:2017-05-23 22:13:11
【问题描述】:

我正在使用异步操作来下载大文件 (>500MB)。我下面的代码会挂起我的应用程序,直到文件下载完成。

public async Task<ActionResult> Download(string filePath, string fileName)
    {
        try
        {
            if(!string.IsNullOrEmpty(filePath))
            {
                filePath = Path.Combine(Code.Config.UploadFilesPath(), filePath);
                string contentType = MimeMapping.GetMimeMapping(fileName);

                if (System.IO.File.Exists(filePath))
                {
                    await GetLargeFile(filePath, fileName);
                }
                else
                {
                    return Content("Requested File does not exist");
                }
            }
        }
        catch(Exception ex) { }
        return Content("");
    }

private async Task GetLargeFile(string fullPath, string outFileName)
{
  System.IO.Stream iStream = null;

        // Buffer to read 10K bytes in chunk:
        byte[] buffer = new Byte[10000];

        // Length of the file:
        int length;

        // Total bytes to read:
        long dataToRead;

        // Identify the file to download including its path.
        string filepath = fullPath;

        // Identify the file name.
        string filename = System.IO.Path.GetFileName(filepath);

        try
        {
            // Open the file.
            iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
                        System.IO.FileAccess.Read, System.IO.FileShare.Read);


            // Total bytes to read:
            dataToRead = iStream.Length;

            Response.Clear();
            Response.ContentType = MimeMapping.GetMimeMapping(filename);
            Response.AddHeader("content-disposition", "attachment; filename=\"" + outFileName + "\"");
            Response.AddHeader("Content-Length", iStream.Length.ToString());

            // Read the bytes.
            while (dataToRead > 0)
            {
                // Verify that the client is connected.
                if (Response.IsClientConnected)
                {
                    // Read the data in buffer.
                    length = iStream.Read(buffer, 0, 10000);

                    // Write the data to the current output stream.
                    Response.OutputStream.Write(buffer, 0, length);

                    // Flush the data to the output.
                    Response.Flush();

                    buffer = new Byte[10000];
                    dataToRead = dataToRead - length;
                }
                else
                {
                    //prevent infinite loop if user disconnects
                    dataToRead = -1;
                }
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException(ex.Message);
        }
        finally
        {
            if (iStream != null)
            {
                //Close the file.
                iStream.Close();
            }
            Response.Close();
        }
}

奇怪的是,如果我在一个全新的 Web 应用程序上使用与上面相同的代码并下载一个大文件(大约 1GB),该应用程序不会挂起,因为我可以在视图之间切换并在下载期间触发 javascript 警报功能过程。

但是对于我的真实项目,不幸的是,应用程序挂起,直到下载完成。

在配置或其他方面有什么我应该考虑的吗?

有什么调试技巧可以查看它是如何在一个全新的应用程序上运行,而不是在我的实际项目上运行的吗?

【问题讨论】:

  • 如果您需要任何帮助,您需要发布 GetLargeFile 的代码
  • Some code to read file &amp; write it to response stream in loop 使用异步 IO?向我们展示代码。
  • 感谢您的回复。代码更新
  • 您没有在异步方法中执行任何异步操作。如果异步方法从不等待,只需将方法标记为async绝对没有,并且该方法将同步运行。这是网络服务器上的坏 juju。将基于 Task 的异步方法与 await 一起用于所有 IO 交互。
  • @Raghu 为什么不自己试一试,如果遇到更多麻烦,请提出新问题?为了让您开始,您的第一个读取操作可能是length = await iStream.ReadAsync(buffer, 0, 10000);

标签: c# asp.net-mvc download async-await


【解决方案1】:

在 Web 应用程序的上下文中,异步仅允许为请求提供服务的线程在进入等待状态时返回到线程池。如果线程正在积极地工作,例如将文件假脱机到响应中,那么它实际上与运行同步相同。

同样,在 Web 应用程序的上下文中,存在请求和响应。客户端发出请求,服务器响应该请求。在这里,该响应是一个文件,因此无论是否异步,线程都将被占用,直到响应完成。在发送响应之前,您不能从操作中“返回”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    相关资源
    最近更新 更多