首页 > 解决方案 > 如何有效地限制 MVC Web 应用程序中从控制器到前端的 SignalR 集线器消息的速率?

问题描述

我的 Web 应用程序的前端有一个进度条,它通过侦听从后端的 SignalR 集线器发送的消息来获取其当前百分比。它跟踪一个长期运行的过程,该过程具有多个阶段和多次迭代。

我最初的设置是每次迭代都简单地发送一条消息。然而,这导致了一些问题,因为前端的迭代速率(以及消息速率)太快了,并且条变得非常跳跃和错误。

因此,我决定按以下方式使用 Stopwatch 对象(SendProgress()告诉集线器向客户端发送消息的过程在哪里):

int progressCount = 1;
var stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();

for(int i=0; i<taskCount; i++)
{

    //PROCESS DONE HERE

    if (stopWatch.Elapsed.TotalMilliseconds >= 500.0)
        {
            SendProgress(taskCount, progressCount, 0, 40);
            stopWatch.Reset();
            stopWatch.Start();
        }
        progressCount++;
}

从而防止消息的发送速度超过每 500 毫秒一次。

这在限制消息速率方面效果很好,但是我注意到性能下降,经过一些研究,我收集到这是由于使用了低效的秒表。

这里有什么更好的方法?我也想过使用Thread.Sleep(),但这只会给算法增加人为的缓慢,这显然很糟糕。有没有办法可以准确地控制消息速率,而不会太慢?

标签: c#asp.netasp.net-mvctimesignalr

解决方案


在控制台应用程序中运行它以查看逻辑是否适用于您想要执行的操作。检查评论以跟踪正在发生的事情(如果您需要我进一步分解,请告诉我)。快乐编码!;)

static void Main(string[] args)
{
    //set the percentage you want to show progress for (eg, every 20%).
    const int updatePercentage = 20;
    //this is just the total of the for loop for this example.
    const int loopMax = 1000000;
    //calculate what 20% of the total is, to set as the check point used to show the progress.
    decimal loopCheck = Convert.ToDecimal(loopMax * (Convert.ToDecimal(updatePercentage) / 100));

    for (int i = 1; i <= loopMax; i++)
    {
        //check if the mod of the current position meets the check point. 
        if ((i % loopCheck) == 0)
        {
            //show the progress...
            Console.WriteLine($"You've reached the next {updatePercentage}% of the for loop ({i.ToString("#,##0")})");
        }
    }
    Console.ReadLine();
}

推荐阅读