C# 几个信号器调用使UI没有响应
我们有一个任务调度器应用程序的这个执行方法,它处理一个进程(System.Diagnostics)收到的输出字符串: SendOutput方法通过信号器将输出发送到UI 问题是,当流程运行一个生成多个输出的命令时,它还会对UI进行多个信号器调用,从而使其锁定 首先,我使用setTimeout Javascript方法解决了UI问题。它不再锁定,但由于一系列超时,它延长了输出的显示时间 我认为处理这些输出的最好方法是通过服务器端,在一段时间内(比如说1到2秒)连接一系列输出,然后将它们发送到UI。我倾向于使用计时器或任务。延迟,但我不能清楚地构建它C# 几个信号器调用使UI没有响应,c#,multithreading,user-interface,signalr,C#,Multithreading,User Interface,Signalr,我们有一个任务调度器应用程序的这个执行方法,它处理一个进程(System.Diagnostics)收到的输出字符串: SendOutput方法通过信号器将输出发送到UI 问题是,当流程运行一个生成多个输出的命令时,它还会对UI进行多个信号器调用,从而使其锁定 首先,我使用setTimeout Javascript方法解决了UI问题。它不再锁定,但由于一系列超时,它延长了输出的显示时间 我认为处理这些输出的最好方法是通过服务器端,在一段时间内(比如说1到2秒)连接一系列输出,然后将它们发送到UI。
希望有人能帮上忙。计时器会帮你分类的。这里有一些代码可以做到这一点(因为我没有得到你的基类)。这在控制台中运行,因此很明显,您必须执行一些工作,例如删除对控制台的调用。这些呼叫都在那里,因此您可以在控制台应用程序中进行测试。这里的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);
}
}
}
看起来您正在将类锁定在进程的输出数据接收事件处理程序中,这可能不是最好的主意 计时器应该为您排序。这里有一些代码可以做到这一点(因为我没有得到你的基类)。这在控制台中运行,因此很明显,您必须执行一些工作,例如删除对控制台的调用。这些呼叫都在那里,因此您可以在控制台应用程序中进行测试。这里的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);
}
}
}
看起来您正在将类锁定在进程的输出数据接收事件处理程序中,这可能不是最好的主意 谢谢你的努力,凯尔。我现在正在使用计时器,但我仍在检查您的示例以进行比较。我可以知道为什么我的代码中的当前锁不是一件好事吗?看起来你的类被称为ExecutionContext,所以你有效地锁定了类型。如果它是公共类型,这可能是一个问题,因为任何东西都可能锁定它并导致死锁。您通常希望锁定线程安全类中的私有对象以防止这种死锁。我使用秒表,但逻辑是相同的。再次谢谢你,凯尔,谢谢你的努力,凯尔。我现在正在使用计时器,但我仍在检查您的示例以进行比较。我可以知道为什么我的代码中的当前锁不是一件好事吗?看起来你的类被称为ExecutionContext,所以你有效地锁定了类型。如果它是公共类型,这可能是一个问题,因为任何东西都可能锁定它并导致死锁。您通常希望锁定线程安全类中的私有对象以防止这种死锁。我使用秒表,但逻辑是相同的。再次感谢你,凯尔。