【发布时间】:2012-04-08 21:54:29
【问题描述】:
我有这个表单,它产生一个新线程并开始在循环中侦听和等待 UDP 数据包。我需要的是使用接收到的字节数来更新 UI。
为此,我设置了一个事件,我将在收到数据包后立即引发,并将收到的字节数作为参数传递。由于我没有在 UI 线程上运行,因此我不能简单地直接更新 UI。这是我目前正在做的事情:
private void EVENTHANDLER_UpdateTransferProgress(long receivedBytes) {
if(InvokeRequired) {
Invoke(new MethodInvoker(() => {
totalReceivedBytes += receivedBytes;
Label.Text = totalReceivedBytes.ToString("##,0");
}));
}
}
但这仍然在与数据包接收循环相同的线程上运行,它不会返回到该循环 - 并等待另一个数据包 - 直到这个 EVENTHANDLER_UpdateTransferProgress 方法返回。
我的问题基本上是关于上述方法中的以下行:
Label.Text = totalReceivedBytes.ToString("##,0");
像这样更新 UI 会减慢数据包的接收速度。如果我把那条线去掉(或注释掉),数据包接收会快得多。
我怎样才能解决这个问题?我认为更多线程是关键,但我不确定如何在这种情况下正确实现它们......我正在使用带有 .NET 2.0 的 Windows 窗体。
编辑:
在我之前的测试中,以上似乎是正确的,实际上在某种程度上可能是正确的。但经过更多测试后,我意识到问题出在整个Invoke(new MethodInvoker(() => { ... })); 上。当我删除它(当然 UI 不会更新)并离开 EVENTHANDLER_UpdateTransferProgress 但继续引发事件时,数据包接收会快得多。
我测试了接收一些平均大约 1.5 秒的文件,而根本没有在事件处理程序上调用 Invoke()。当我在事件处理程序中调用 Invoke() 时,即使没有更新 UI 中的任何控件或执行任何操作(换句话说,匿名方法体是空的),它也需要更长的时间,大约 5.5 秒。你可以看到这是一个很大的不同。
还有什么可以改进的吗?
【问题讨论】:
-
您使用的是什么版本的 .NET?
-
@SeanThoman 对于这个特定的应用程序,.NET 2.0。
-
看到这个线程 - stackoverflow.com/questions/661561/…
-
@SeanThoman 我已经实现了接受的答案,但我似乎没有注意到我原来的实现有任何区别。但是,我做了更多的测试,问题似乎出在 Invoke 本身上,这实际上是减慢了整个事情的速度。对于那个很抱歉。我必须更新问题...
标签: c# multithreading sockets packet-capture ui-thread