有一个ThreadTimer,每10秒执行一次下面的do().
void do()
{
for(i = 0, i < 10000, i++)
{
IAsyncResult removeResult = this.BeginVoke(地图删除图元);
IAsyncResult insertResult = this.BeginVoke(地图重绘图元);
this.EndInvoke(removeResult);
this.EndInvoke(insertResult);
}
}
程序大概运行过程就是这样。
现在的问题是,在这段代码执行时,地图就不能执行其它操作,而且主界面也会很卡,几乎损失对其它操作的响应。
请问这是什么原因?要怎么解决呢?
可能重绘的太频繁了。
1、可以考虑分区块重绘
2、ThreadTimer也会造成重入的情况,即第一次还没完成,第二次又触发了。
3、你在主线程代码中调用了EndInvoke方法,这实际上也导致你整个for循环是同步执行的。可以考虑把你整个for里面的代码放入一个辅助线程中执行
4、可以考虑给一个计数变量,在辅助线程开始时+1,结束时-1.用此变量来限制任务数量,比如到100时就先让线程暂定下。注意计数的自增递减要用interlocked。。(或则使用信号量来限流Semaphore)
谢谢,我解决了,不过遇到一个问题就是这个线程每次的执行时间都会增加,要怎么解决呢?
@Selway: 哪个线程?是指重入的问题?可否贴出你现在调整后的代码
原因很简单,你在极短的时间内执行了20000个UI操作,根据每个操作的时长,和默认线程池大小,估计能够达到 100个每秒。
UI是采用的单线程单元模型,建议你按顺序执行 20000 个操作,不要用多线程来执行。
我试了一下,这样效果也是一样的
@Selway: 这个场景比较复杂,一是对图形绘制知识的掌握,还有就是对需求的充分理解。比如,我假设用户对实时性要求不高,并且地图重绘图元操作时间极短,那么可以在一个循环内去执行绘制,并在每10次绘制后调用一次Application.DoEvent(此方法会通知UI线程先去处理下别的UI消息)。还可以在绘制前禁止重绘,然后在所有绘制完成后,再启用重绘。可以利用双缓冲模式来绘制你的图形。
@Selway: 我不太了解你的需求,也不知道你的地图是如何绘制的。因此我能给你的建议是你应该理解Windows窗体程序的消息机制,明白了后,你应该可以找到一个切入点把你的应用优化成符合该消息机制的方式来运行。
@Launcher: 谢谢,我解决了,不过遇到一个问题就是这个线程每次的执行时间都会增加,要怎么解决呢?
那个EndEnvoke方法好像不是那么调用的.应该是放在BeginInvoke的内部..
你试试看,我给你一个学习时的例子,不知道改成这样有没有效果.
using System; using System.Security.Permissions; using System.Threading; class ThreadInterrupt { //定义一个委托 public delegate void DoSomething(); static void Main(string[] args) { //1.实例化一个委托,调用者发送一个请求,请求执行该方法体(还未执行) DoSomething doSomething = new DoSomething( () => { Console.WriteLine("如果委托使用beginInvoke的话,这里便是异步方法体"); Thread.Sleep(5000); //4,实现完这个方法体后自动触发下面的回调函数方法体 }); //3 。调用者(主线程)去触发异步调用,采用异步的方式请求上面的方法体 IAsyncResult result = doSomething.BeginInvoke( //2.自定义上面方法体执行后的回调函数 new AsyncCallback ( //5.以下是回调函数方法体 //asyncResult.AsyncState其实就是AsyncCallback委托中的第二个参数 asyncResult => { doSomething.EndInvoke(asyncResult); Console.WriteLine(asyncResult.AsyncState.ToString()+"XX"); } ) , "BeginInvoke方法的第二个参数就是传入AsyncCallback中的AsyncResult.AsyncState,我们使用时可以强转成相关类型加以使用"); //DoSomething......调用者(主线程)会去做自己的事情 for(int i=0;i<99999;i++) { Console.WriteLine(i); Thread.Sleep(1000); } Console.ReadKey(); } }
注意EndInvoke的位置,另外,如果同时开2000个线程,如果机器配置不怎么样的话,肯定会很卡的.
如果你用主线程 这样 肯定会卡,用子线程去试试