C#窗体由于waitOne而减慢
本文关键字:waitOne 窗体 | 更新日期: 2023-09-27 17:59:03
我遇到了一个小问题,试图使用JSON对设备到设备的porgram进行编码。
我的设备对设备运行良好,我正在使用它通过自制的D2D服务器将JSON发送到其他设备。所以我的一个客户端正在向另一个名为"服务器"的客户端发送请求,该服务器正在做一些事情(在Asterisk服务器上做一些请求),一切都可以。
但我面临一个问题:当我的客户端向服务器发送请求时,我会在autoResetEvent上用waitOne等待服务器的答复。根据请求,我的表单将显示一个弹出窗口。但我的表单显示弹出窗口的速度很慢,我想这是由于那些waitOne,我可以在不到3秒的时间内发送大约10个请求,所以我认为我的表单速度很慢。
基本上,我使用的是一个在套接字上读取数据的线程,当我的数据完成时(检索整个Json),我发送一个事件,然后我必须释放读取线程,所以我正在执行"BeginInvoke",这样我的表单将处理事件:
_sync.BeginInvoke(ChannelChange, new Object[] {this, ec});
在显示弹出窗口后,我的表单正在处理多个其他事件,它正在向服务器进行一些请求(因此线程在多次请求期间停止)。
所以我想,这就是为什么我的弹出窗口显示得很慢的原因。所以我的问题是如何避免这种减速?
小简历:
MyForm正在使用一个客户端,该客户端包含一些方法,如"retrieveChannelById"。当我的读取线程检索一个完整的Json时,它会抛出一个调用我的表单的事件(如果我不用我的表单调用该事件,我的阅读线程将被停止,这是最糟糕的)。我的表单正在执行一些客户端方法,如"retrieveChannelById",将线程设置为暂停一段时间(通常不到1秒,但它很快就完成了大量请求)。
所以我想知道,如何在不暂停表单线程的情况下指定一个线程来执行这些方法?
但是,当我处理一个事件时,我还是在做
Channel chan = Client.GetChannelByChanID(e.ChannelId);
我真的不知道如何处理表单的速度减慢,我必须在其他线程中执行这些方法吗?(我想这不会改变任何事情,因为我的表单必须等待另一个线程来获得正确的通道?)。我需要一个解决方案,这样我的表单线程就不会设置在WaitOne上,我想这是我的问题。
这真的很难解释,实际上。。。
这是我检索方法的代码ChannelById:
SendD2DMessage("*", "server", "{'"classname'":'"GetChannelByChanID'",'"chanID'":'"" + chanID + "'"}");
waitingData = "reponseGetChannelByID";
if (this._messageRecieved.WaitOne(5000))
{
try
{
if (dataRecieved == "null")
{
Console.WriteLine("But data null");
return null;
}
else
{
Channel chan = JsonConvert.DeserializeObject<Channel>(dataRecieved);
Console.WriteLine("Channel received : " + chan.Extension);
return chan;
}
}
catch (Exception ex)
{
SynsipClientLog.Log("Error while deserializing Channel Object in GetChannelByID Method :" + ex.Message);
return null;
}
}
else
{
waitingData = "";
Console.WriteLine("Channel NOT RECEIVED");
SynsipClientLog.Log("No response from D2DConsole in GetChannelByChanId method");
return null;
}
这是ChannelChange代码,这个代码是我的主要形式
void SynsipCli_ChannelChange(object sender, SynsipRemoteChannelChangeEventsArgs e)
{
try
{
//Console.WriteLine("test ChannelChange");
Channel chan = SynsipCli.GetChannelByChanID(e.ChannelId);
Channel linkedChan = null;
if (chan != null && chan.LinkedChannelID.Length>1)
{
linkedChan = SynsipCli.GetChannelByChanID(chan.LinkedChannelID);
}
// alertes pour les trunck
if (e.Channelcategory == ChannelCategory.Trunck && !MenuDoNotDisplay.Checked)
{
bool isGeneralNumber = false;
if (chan != null)
{
foreach (string str in SynsipCli.AstParameters.GeneralNumbers)
{
if (chan.CallerIDNum.Contains(str) || chan.LinkedCallerID.Contains(str) || chan.DNIS.Contains(str) || chan.Extension.Contains(str))
isGeneralNumber = true;
}
if (chan.State != ChannelState.Down && chan.State != ChannelState.Hangup && chan.State != ChannelState.Unknow && (chan.LinkedCallerID == Extension || chan.CallerIDNum == Extension || isGeneralNumber))
{
LaunchAlert(chan);
}
}
}
else if (linkedChan != null && linkedChan.ChannelCategory == ChannelCategory.Trunck)
{
bool isGeneralNumber = false;
if (linkedChan != null)
{
foreach (string str in SynsipCli.AstParameters.GeneralNumbers)
{
if (linkedChan.CallerIDNum.Contains(str) || linkedChan.LinkedCallerID.Contains(str) || linkedChan.DNIS.Contains(str))
isGeneralNumber = true;
}
if (linkedChan.State != ChannelState.Down && linkedChan.State != ChannelState.Hangup && linkedChan.State != ChannelState.Unknow && (linkedChan.LinkedCallerID == Extension || linkedChan.CallerIDNum == Extension || isGeneralNumber))
{
LaunchAlert(linkedChan);
//LaunchAlert(tchan);
}
}
}
if (((chan != null && (chan.CallerIDNum == txtExtention.Text || chan.LinkedCallerID == txtExtention.Text)) || e.Extension == txtExtention.Text) && !MenuDoNotDisplay.Checked) // alertes pour le local
{
string ext = SynsipCommunicator.Properties.Settings.Default.Extention;
Extension exten = SynsipCli.GetExtension(ext);
foreach (Channel tchan in exten.Channels)
{
if (tchan != null && tchan.CalllType == CallType.Internal)
{
LaunchAlert(tchan);
}
}
}
// suppression des alerts qui ne doivent plus exister
for (int i = 0; i < Alerts.Count; i++)
{
Channel tchan = SynsipCli.GetChannelByChanID(Alerts[i].chanId);
if (tchan == null)
Alerts[i].Close();
else if (tchan.State == ChannelState.Down || tchan.State == ChannelState.Hangup || tchan.State == ChannelState.Unknow)
Alerts[i].Close();
}
}
catch (Exception exe)
{
//Console.WriteLine("ERREUR CHANNEL CHANGE " + exe.Message);
}
}
LaunchAlert方法只是检查我的Channel对象中的一些东西,创建一个帧,然后显示该帧:
if (!MenuDoNotDisplay.Checked)
{
ShowWindow(frma.Handle, 4); //Pour éviter de prendre le focus
SetWindowPos(frma.Handle, -1, frma.Location.X, frma.Location.Y, frma.Width, frma.Height, 0x0010);
}
不要在UI线程上执行任何阻塞等待(如event.WaitOne()
)。这将导致您所描述的死行为,因为在此期间UI无法自我更新。
相反,您应该异步工作:只在UI线程上启动操作,然后立即返回。操作完成后,切换回UI线程(例如使用BeginInvoke
),评估结果以及您的操作是否仍然必要,并根据操作结果更新UI。
如果你想要像5s这样的超时,那么异步启动发送操作,并在UI中异步并行启动计时器。两者都应该在UI线程中完成。然后看看你的计时器是先结束还是先收到操作结果并处理这种情况。
您还可以将Send操作封装在C#TPL Task对象中,或者使用C#async/await特性使整个代码更加可读和可组合。