【问题标题】:Blazor Server File Upload Very SlowBlazor 服务器文件上传非常慢
【发布时间】:2021-07-07 22:12:34
【问题描述】:

更新

我暂时搁置了这一点,但我现在又回来了。我找不到任何有帮助的东西。有谁知道我可以调试 CopyToAsync 函数内部发生的事情的方法,或者我可以看到瓶颈在哪里的方法。从客户端计算机端或 Web 服务器端。我做开发人员已经有一段时间了,但对 Web 开发很陌生,所以我不熟悉浏览器开发工具或任何可以帮助我找到这个问题的东西。任何建议都将不胜感激,因为我完全被困在这一点上。

问题

我的上传速度似乎很慢。上传一个 8MB 的文件大约需要 22 或 23 秒。在 LAN 内,网络服务器启动需要 2 或 3 秒。通过一些日志记录,我缩小了所有时间都花在了对 Stream.CopyToAsync() 的调用上。在底部,我放置了两个日志输出以显示本地和远程之间的上传差异。 CopyToAsync 之前和之后的所有其他代码都运行得很快。我已经包含了我在下面制作的 blazor 组件的代码。

研究

我已经检查了以下案例以及许多其他阅读材料,但似乎还没有发现任何有用的东西。

Should I call ConfigureAwait(false) on every awaited operation

Increase Speed for Streaming Large(1-10 gb) files .Net Core

Extremely Slow file upload to a Blazor Server app deployed as Azure Web App

我的尝试

正如您在代码中看到的那样,我尝试向 FileStream 添加一些 FileOptions,但这对速度没有影响。我也尝试过 ConfigureAwait 但这并没有提高速度并且在第一个文件之后也崩溃了。我认为这是因为这是在 UI 线程中。至少这是我从研究中假设的。我对编程并不陌生,但我对 Web 编程尤其是 Blazor 很陌生。

其他要点

服务器和远程客户端都位于具有高速互联网的位置(在同一城市内),并且网络服务器的负载不重。

问题

8MB 的 23 秒对于代码的设计方式是正常的还是你认为这也太夸张了?

我的代码是正确的方法吗?除了速度之外,它的功能确实非常可靠。

有什么建议可以尝试或研究来解决这个问题吗?

代码

@using System.IO
@inject SessionService session
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment env
@inject IJSRuntime JSRuntime

@if (showMessage)
{
    <div style="font-size: 20px;" class="alert-danger border-danger">
        <p>@userMessage</p>
    </div>
}

<button class="btn btn-primary m-2" onclick="document.getElementById('filepicker').click()" disabled="@disabled">@buttonText</button>
<InputFile id="filepicker" OnChange="@OnInputFileChange" hidden multiple="@multipleFiles" />

@code
{
    [Parameter] public EventCallback<FileModel> OnFileAdd { get; set; }
    [Parameter] public EventCallback<int> OnUploadStart { get; set; }
    [Parameter] public EventCallback<bool> OnUploadEnd { get; set; }
    [Parameter] public string buttonText { get; set; } = "Upload";
    [Parameter] public bool multipleFiles { get; set; } = false;
    [Parameter] public int callBackRefID { get; set; } = 0;
    private IReadOnlyList<IBrowserFile> selectedFiles;
    private bool showMessage = false;
    private bool disabled = false;
    private MarkupString userMessage;

    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        if (e.FileCount > 0)
        {
            disabled = true;
            await JSRuntime.InvokeAsync<string>("console.log", "Starting " + e.FileCount + " files - " + DateTime.Now.ToString());
            await OnUploadStart.InvokeAsync(e.FileCount);
            selectedFiles = e.GetMultipleFiles(e.FileCount);

            foreach (var file in selectedFiles)
            {
                await JSRuntime.InvokeAsync<string>("console.log", "Starting " + file.Name + " - " + DateTime.Now.ToString());
                Stream stream = file.OpenReadStream((long)2147483648);
                var path = $"{env.WebRootPath}\\Uploads\\{file.Name}";

                //FileOptions had no effect on performance
                FileStream fs = File.Create(path, 1048576, FileOptions.Asynchronous | FileOptions.SequentialScan);
                //FileStream fs = File.Create(path, 1048576);

                await JSRuntime.InvokeAsync<string>("console.log", "Before stream.CopyToAsync - " + DateTime.Now.ToString());
                await stream.CopyToAsync(fs, 1048576);
                //ConfigureAwait causes crash after first file is done.
                //await stream.CopyToAsync(fs, 1048576).ConfigureAwait(false);
                await JSRuntime.InvokeAsync<string>("console.log", "After stream.CopyToAsync - " + DateTime.Now.ToString());

                stream.Close();
                fs.Close();

                FileModel upFile = new();
                upFile.S_ID = session.CurrentUser.ID;
                upFile.Name = file.Name;
                upFile.DisplayName = "";
                upFile.Descr = "";
                upFile.ContentType = file.ContentType;

                if (upFile.GetFileData(path, file.ContentType) == false)
                {
                    userMessage = new(upFile.ErrMsg);
                    showMessage = true;
                    await OnUploadEnd.InvokeAsync(false);
                    return;
                }

                await OnFileAdd.InvokeAsync(upFile);
                await JSRuntime.InvokeAsync<string>("console.log", "Finished " + file.Name + " - " + DateTime.Now.ToString());
            }

            await OnUploadEnd.InvokeAsync(true);
            await JSRuntime.InvokeAsync<string>("console.log", "Finished - " + DateTime.Now.ToString());
            disabled = false;
        }
    }
}

本地日志

blazor.server.js:1 Starting 3 files - 2021-04-12 2:01:33 PM

blazor.server.js:1 Starting IMG_7830.JPG - 2021-04-12 2:01:33 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:33 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:36 PM
blazor.server.js:1 Finished IMG_7830.JPG - 2021-04-12 2:01:37 PM

blazor.server.js:1 Starting IMG_7831.JPG - 2021-04-12 2:01:37 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:37 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:40 PM
blazor.server.js:1 Finished IMG_7831.JPG - 2021-04-12 2:01:41 PM

blazor.server.js:1 Starting IMG_7832.JPG - 2021-04-12 2:01:41 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 2:01:41 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 2:01:43 PM
blazor.server.js:1 Finished IMG_7832.JPG - 2021-04-12 2:01:44 PM

blazor.server.js:1 Finished - 2021-04-12 2:01:44 PM

远程日志

blazor.server.js:1 Starting 3 files - 2021-04-12 12:01:44 PM

blazor.server.js:1 Starting IMG_7830.JPG - 2021-04-12 12:01:45 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:01:45 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:07 PM
blazor.server.js:1 Finished IMG_7830.JPG - 2021-04-12 12:02:08 PM

blazor.server.js:1 Starting IMG_7831.JPG - 2021-04-12 12:02:08 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:02:08 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:30 PM
blazor.server.js:1 Finished IMG_7831.JPG - 2021-04-12 12:02:31 PM

blazor.server.js:1 Starting IMG_7832.JPG - 2021-04-12 12:02:31 PM
blazor.server.js:1 Before stream.CopyToAsync - 2021-04-12 12:02:31 PM
blazor.server.js:1 After stream.CopyToAsync - 2021-04-12 12:02:53 PM
blazor.server.js:1 Finished IMG_7832.JPG - 2021-04-12 12:02:54 PM

blazor.server.js:1 Finished - 2021-04-12 12:02:54 PM

【问题讨论】:

    标签: c# file stream blazor blazor-server-side


    【解决方案1】:

    对我来说,将 8MB 的文件上传到我的服务器只需不到一秒的时间。我定期将 50MB 库存照片图片上传到我的网站——包括处理和调整图片大小,每个平均需要几秒钟。

    所以,正如您所怀疑的,这里有问题。

    乍一看,我所做的唯一显着不同的是我没有为流副本指定缓冲区长度。不过,我想你已经玩过所有这些东西了。

    你说服务器在同一个城市,但是什么样的服务器呢?我假设您没有使用共享主机或类似的东西,对吧?在注册 Microsoft VM 之前,我使用了 Godaddy 大约 2 天。

    【讨论】:

    • 我的进程也将大小调整为 2 种不同的大小并保存到数据库中。所有这一切都在 1 秒内完成。缓冲区是我尝试的第一件事。我只是尝试删除指定的大小,但结果相同。服务器是我办公室的物理服务器。我没有规格,但我不怀疑这是问题所在,因为服务器负载非常轻。
    猜你喜欢
    • 2022-07-14
    • 2020-12-08
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多