使用BeginInvoke时无响应的UI

时间:2010-03-24 19:33:11

标签: .net multithreading user-interface

Bckground
我有一个用C#编写的网络应用程序。我的服务器程序有一个UI和几个通信线程,从tcp套接字读取并在控制器UI上显示消息。

通过单独的线程完成与每个客户端的通信。当我从一个客户端收到一些消息流时,该客户端的线程在UI上写入,这是一个表单上的richtextbox。

我调用表单的SetTextHelper(字符串文本)方法。

看起来像这样

private delegate void MyTextUpdateHandler(string text);
public void SetTextHelper(string text)
{
   BeginInvoke(new MyTextUpdateHandler(SetText), new object[] { text });
}

public setText(string text)
{
   richtext.Text+= text;
}

问题
  - 如果我使用BeginInvoke,当我将大量数据流写入UI时,我的UI完全没有响应   - 调用解决了这个问题,但我读到了多线程环境,其中很多人共享相同的资源调用可能导致死锁我分享大约16个线程之间的共同ichtextbox   - 对我的情况有什么好处?

3 个答案:

答案 0 :(得分:9)

您经常调用BeginInvoke()。 UI线程将在委托执行其正常职责之前调度委托,例如绘制控件和响应鼠标。如果委托目标正在做很多工作(将文本附加到RTB是昂贵的)或者你只是充满了请求,它就不再能够正常工作了。用户界面将冻结。这很容易发生,每秒大约1000个调用就足够了。

解决这个问题的关键是要意识到经常调用它是浪费精力。人眼无法以每秒25次的速度感知更新。因此缓冲文本直到自上次更新以来已经过了50毫秒。 Environment.TickCount是一个便宜的计时器。

还要注意,实际上生成文本的速度可能比附加到RTB的速度快。这需要限制线程。这很简单:使用Invoke而不是BeginInvoke。

答案 1 :(得分:3)

Invoke不应导致死锁,除非您在进行调用时拥有锁定...但BeginInvoke也不应使UI无响应。可能问题是你只是经常尝试更新文本框?也许缓冲传入的文本更多?例如,每半秒更新一次UI,而不是每次读取任何数据时都会更新。

答案 2 :(得分:2)

您可能只是花费所有时间设置文本。

尝试用普通RichTextBox替换TextBox;它应该快得多。