几个SignalR调用使UI无响应

时间:2017-09-21 15:28:43

标签: c# multithreading user-interface signalr

我们确实有这个任务调度程序应用程序的Execute方法,它处理收到的输出字符串买一个进程(System.Diagnostics):

    public override void Execute()
    {
        // ... more logic above 

        Process = new Process { StartInfo = { FileName = fileName, Arguments = args } };
        Process.StartInfo.UseShellExecute = false;
        Process.StartInfo.RedirectStandardOutput = true;
        Process.StartInfo.RedirectStandardError = true;
        Process.EnableRaisingEvents = true;
        Process.Exited += ProcessExited;
        Process.OutputDataReceived += new DataReceivedEventHandler(
                delegate(object sender, DataReceivedEventArgs e)
                {
                    if (e.Data != null)
                    {
                        lock (ExecutionContext)
                        {
                            ExecutionContext.AppendOutput(e.Data);
                        }
                    }
                }
            );

        Process.Start();
        Process.BeginOutputReadLine();
    }


    public void AppendOutput(string str)
    {
        // To do: Append strings to the _currentOutput within a period of time
        _currentOutput += str + Environment.NewLine;

        // Before doing the following
        SendOutput(_currentOutput);

        // Reset the variable
        _currentOutput = "";
    }

SendOutput方法通过SignalR将输出发送到UI。

问题是当Process运行一个产生多个输出的命令时,它还会对UI进行几次SignalR调用,使其锁定。

首先,我使用setTimeout Javascript方法解决了UI问题。它不会再锁定,但由于一系列超时,它会延长输出的显示。

我认为处理这些输出的最佳方法是通过服务器端在一段时间内连接一系列输出,比如说1到2秒,然后再将它们发送到UI。我倾向于使用Timer或Task.Delay,但我无法清楚地构建它。

希望有人帮忙。

1 个答案:

答案 0 :(得分:2)

计时器应该为您排序。这里有一些代码会执行此操作(因为我没有得到你的基类,所以这是一个黑客攻击)。这在控制台中运行,所以显然你必须做一些工作,比如删除对控制台的调用。这些调用是在那里你可以在控制台应用程序中测试它。这里的SendOutput方法只是写入控制台,但你只是删除它,它应该调用你的signalR客户端。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Timers;

namespace bufferOutput
{
    public class Processor
    {
        private object bufferLock = new object();
        private StringBuilder sb = new StringBuilder();
        private Timer updateTime = new Timer(250);//fire every quarter second: a reasonable time for a web page to update

        public void Execute(string fileName, string args)
        {
            var process = new Process { StartInfo = { FileName = fileName, Arguments = args } };
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.EnableRaisingEvents = true;
            process.Exited += ProcessExited;
            process.OutputDataReceived += AppendOutput;
            process.Start();
            updateTime.Elapsed += updateTime_Elapsed;
            process.BeginOutputReadLine();
            updateTime.Start();
            Console.Title = "Buffered data: Press the Enter key to exit the program.";
            Console.ReadLine();
            ProcessExited(this, EventArgs.Empty);
            Console.ReadLine();
        }

        void updateTime_Elapsed(object sender, ElapsedEventArgs e)
        {
            string output = "";
            lock(bufferLock)
            {
                output = sb.ToString();
                if (output != "")//if there was anything in the strng builder, clear it
                    sb = new StringBuilder();
            }
            if (output != "")
                SendOutput(output);
        }

        public void ProcessExited(object sender, EventArgs e)
        {
            updateTime.Stop();
            Console.Title = "writing out buffer: Press the Enter key to exit the program.";
            updateTime_Elapsed(this, null);
            SendOutput("Done");
        }

        public void AppendOutput(object sender, DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                lock (bufferLock)
                    sb.AppendLine(e.Data);
            }
        }

        public void SendOutput(string output)//placeholder for the client side
        {
            Console.WriteLine(output);
        }
    }
}

看起来您已经在过程的输出数据接收事件处理程序中锁定了您的类,这可能不是最好的主意。