问题描述
项目中有两A(),B()两个方法,当线程执行A方法时,在A中调用了BprivatevoidA(){doublex,y,z;//接收来自单片机的数据//执行速度非常快...........line.add(x,y);B(x,y,z);}privatevoidB(doublenx,doubleny,double,nz){//处理大量计算数据,延迟较大delay(100000)...........}上述两方法,首先执行A,代码很少,其中主要向tchart中画线,但B中有大量数据处理,比较耗时,会很拖延A的执行速率,界面显示数据时很卡.现在,为了不影响主界面的显示,想把B方法单独开一个线程,但问题来了,新开一个线程,B方法需要的参数x,y,z需要从A中来,而且怎样保证同步性(A执行一次,B也必须执行一次)不知道异步委托能不能行,但又不太熟悉,看了半天,资料也不太明白希望大家有什么好的解决方案,成分感激!
解决方案
解决方案二:
我也遇到了这问题,我接受到数据一边存一边显示。显示单独开了一个线程,定时去显示收到的数据。现在的问题就是无法保证同步。不知怎么解决。所以帮顶!
解决方案三:
引用1楼u010018424的回复:
我也遇到了这问题,我接受到数据一边存一边显示。显示单独开了一个线程,定时去显示收到的数据。现在的问题就是无法保证同步。不知怎么解决。所以帮顶!
我是在串口线程中,接收到数据时,先存储在数组中,再sendmessage在主窗体的WndProc中进行处理时调用了A方法用异步或委托都不好用
解决方案四:
首先,AB两部分都必须放在工作线程中,因为它们需要同步,只有它们都脱离了主线程才能避免界面的悬挂。至于这两个线程之间的同步,可以使用AutoResetEvent(信号量),或者lock(监视器、临界区)google生产者-消费者模式http://www.cnblogs.com/LoveJenny/archive/2011/05/31/2060777.html
解决方案五:
A产生的数据,先放到队列里,然后开N个线程去队列里取数据处理必须是多对一的形式,否则A快B慢,处理不过来,同步还是会卡住A
解决方案六:
该回复于2015-10-31 23:38:35被版主删除
解决方案七:
引用楼主wuhz520的回复:
项目中有两A(),B()两个方法,当线程执行A方法时,在A中调用了BprivatevoidA(){doublex,y,z;//接收来自单片机的数据//执行速度非常快...........line.add(x,y);B(x,y,z);}privatevoidB(doublenx,doubleny,double,nz){//处理大量计算数据,延迟较大delay(100000)...........}上述两方法,首先执行A,代码很少,其中主要向tchart中画线,但B中有大量数据处理,比较耗时,会很拖延A的执行速率,界面显示数据时很卡.现在,为了不影响主界面的显示,想把B方法单独开一个线程,但问题来了,新开一个线程,B方法需要的参数x,y,z需要从A中来,而且怎样保证同步性(A执行一次,B也必须执行一次)不知道异步委托能不能行,但又不太熟悉,看了半天,资料也不太明白希望大家有什么好的解决方案,成分感激!
可以将A产生的数据暂存到List或者队列,A存入完成后就返回;另外一个线程执行B的逻辑,这样能保证顺序,实现处理的异步化
解决方案八:
这个问题我之前遇到过,用队列比较合适,A方法用一个线程,将数据放入队列,B方法用一个线程,去队列读取数据执行,这样做效果不错。//循环读取数据库到队列publicvoidReader(Int32n){Stringid=String.Empty;Stringm_id;Stringh_id;Stringpic_name;Stringpic_url;Stringlist;Stringm1;Stringm2;Stringm3;sql_classconn=newsql_class();while(Stop==false){if(qu.Count<200){SqlDataReadersqlread=conn.getread("SELECTTOP2000,,,,,,,,FROMwhereid>"+key+"anderr="+n+"");if(sqlread.HasRows){while(sqlread.Read()){try{Monitor.Enter(qu);//锁定队列;id=sqlread.ToString();m_id=sqlread.ToString();h_id=sqlread.ToString();pic_name=sqlread.ToString();pic_url=sqlread.ToString();list=sqlread.ToString();m1=sqlread.ToString();m2=sqlread.ToString();m3=sqlread.ToString();qu.Enqueue(id+"#"+m_id+"#"+h_id+"#"+pic_name+"#"+pic_url+"#"+list+"#"+m1+"#"+m2+"#"+m3);}catch{}finally{Monitor.Exit(qu);//解锁队列}}key=Convert.ToInt32(id);}else{break;//终止任务循环}}Delay(2000);}}publicvoidrun(){Stringf=String.Empty;while(qu.Count>0&&Stop==false){try{Monitor.Enter(qu);//锁定队列;f=qu.Peek().ToString();qu.Dequeue();//删除队列第一条}catch{}finally{Monitor.Exit(qu);//解锁队列;}down_pic(f);//下载图片Delay(1000);}}
可以参考下,操作队列时需要锁定,你的B方法,可以用多线程处理,加快速度,我这个项目就是,用了10个线程来执行run()方法。
解决方案九:
拿到参数就开启线程处理,楼主说的一点都不冲突啊.
解决方案十:
引用8楼zhengnan2012的回复:
拿到参数就开启线程处理,楼主说的一点都不冲突啊.
不太明白你的意思,能详细讲解一下吗?谢谢!
解决方案十一:
引用6楼xian_wwq的回复:
可以将A产生的数据暂存到List或者队列,A存入完成后就返回;另外一个线程执行B的逻辑,这样能保证顺序,实现处理的异步化
初步实现思路也就只有这样,但我目前是将采集的数据,先存入到已经定义好的二维数组中,B方法中很多地方需要对这个数组中的数据进行二次计算,将这个数组改为List,不太好改。我的想法是,用一个累加器在A中计数,另一线程在B方法中计数,只要B中计数器不超过A中计数器就一直循环读取A存入的数据正在测试中。。。。。。
解决方案十二:
引用7楼phuai007的回复:
这个问题我之前遇到过,用队列比较合适,A方法用一个线程,将数据放入队列,B方法用一个线程,去队列读取数据执行,这样做效果不错。可以参考下,操作队列时需要锁定,你的B方法,可以用多线程处理,加快速度,我这个项目就是,用了10个线程来执行run()方法。
谢谢7楼的,受启发了
解决方案十三:
Task.WaitAll试看
解决方案十四:
先从业务流程重构,最后再说技术问题。你确定“A执行一次,B也必须执行一次”吗?这样你永远也不可能“看起来流畅”,而且堆积越来越多的垃圾(“队列”这个词儿只是一个噱头,解决不了问题)。通常会丢弃一些B,比如说仅执行“来得及执行的”最后一个B。不过这需要从实际的业务逻辑出发来设计。如果你懒得具体分析业务流程,就没有什么可能进行优化。一味地追求“技术”词儿,那么也根本不能用好什么技术。
解决方案十五:
引用11楼wuhz520的回复:
谢谢7楼的,受启发了
如果你原本被子线程调用的A,阻塞到一个“队列”,还要每一次放入队列时都延时2秒钟;而从队列上取出处理也是阻塞的,还要每一次都延时1秒钟,那么你就应该看到这跟你的程序要求“完全是一个地下一个天上”。
解决方案:
引用8楼zhengnan2012的回复:
拿到参数就开启线程处理,楼主说的一点都不冲突啊.
lz的出发点是“总共”只有两个线程的那种模式,而不是按需分配线程。
解决方案:
就你目前的情况,使用lock确实是可以解决问题的。定义一个全局的变量,在B中lock变量,在A中也lock变量。现在问题是如果A频繁被触发调用,而B又需要大量时间来计算,就会造成不匹配,不能完成你要求的A执行一次,B也执行一次的要求了。
解决方案:
你用笨法想A往仓库里放货物,B从仓库里取获取A放的快,B取的慢总有仓库放满了的时候要么A降低速度,B取出一个,A才能放进去一个要么货物就得丢弃一部分
解决方案:
要么就不能一个人放货,一个人取货既然取货慢,你多弄几个人,让取货快点不就得了
解决方案:
如果两个线程,然后A执行一次B执行一次那么就会是这种效果你连点三次,然后B后面慢慢执行.然后控制只有两处线程的方式,我感觉就是信号量的方式来控制.
解决方案:
如17#所说的.其它的方式还不好控制,包括Task.WaitAll也不好控制,这个只是保证在所有的线程执行完,但是要控制数量还是信号量方式好控制.
解决方案:
引用13楼sp1234的回复:
先从业务流程重构,最后再说技术问题。你确定“A执行一次,B也必须执行一次”吗?这样你永远也不可能“看起来流畅”,而且堆积越来越多的垃圾(“队列”这个词儿只是一个噱头,解决不了问题)。通常会丢弃一些B,比如说仅执行“来得及执行的”最后一个B。不过这需要从实际的业务逻辑出发来设计。如果你懒得具体分析业务流程,就没有什么可能进行优化。一味地追求“技术”词儿,那么也根本不能用好什么技术。
首先谢谢你的讲解,B中只是对A中存入数组的数据进行分析计算,得出相应的结果,每一个数据都不能丢的,再后面很多地方还要对数组进行操作。
解决方案:
引用16楼mjp1234airen4385的回复:
就你目前的情况,使用lock确实是可以解决问题的。定义一个全局的变量,在B中lock变量,在A中也lock变量。现在问题是如果A频繁被触发调用,而B又需要大量时间来计算,就会造成不匹配,不能完成你要求的A执行一次,B也执行一次的要求了。
有点不太明白你的意思,用lock虽然能保存A,B同步,但会拖慢了A的执行速度
解决方案:
引用18楼Z65443344的回复:
要么就不能一个人放货,一个人取货既然取货慢,你多弄几个人,让取货快点不就得了
如果开多个线程都去处理B的话,那么怎样保存几个线程在取数据时不重复,乱序呢?
解决方案:
用队列比较合适,A方法用一个线程,将数据放入队列,B方法用一个线程,去队列读取数据执行
学习了
解决方案:
引用22楼wuhz520的回复:
Quote: 引用16楼mjp1234airen4385的回复:
就你目前的情况,使用lock确实是可以解决问题的。定义一个全局的变量,在B中lock变量,在A中也lock变量。现在问题是如果A频繁被触发调用,而B又需要大量时间来计算,就会造成不匹配,不能完成你要求的A执行一次,B也执行一次的要求了。有点不太明白你的意思,用lock虽然能保存A,B同步,但会拖慢了A的执行速度
就是你理解的意思。试试这个想法:每次当A从单片机接收数据完毕后,把数据插入一个列表List,数据包括:唯一ID(自己生产GUID),x,y,z,方法B执行完毕的回调函数(委托)。然后开启一个线程把前四个参数传入线程中,执行B方法,执行完毕,调用委托。(此处可以使用包含线程的类去实现)这样不影响A的执行,不影响UI,B执行完毕后,调用回调函数可以知道执行结果,并且可以根据执行再次更行UI。如果使用委托会影响UI的话,可以使用简单类型的参数,在B方法所在线程里根据ID设置参数,然后在UI里做个定时扫描来更新UI。
解决方案:
引用23楼wuhz520的回复:
如果开多个线程都去处理B的话,那么怎样保存几个线程在取数据时不重复,乱序呢?
保证不重复,加Lock啊,一次只能一个线程去取数据.反正是取数据其实很快,处理的慢而已,不会拖慢A的还是用出入库做比喻,入库和出库都要填单子,填单子其实很快,搬运慢为了保证数量的准确,必须进一个或者出一个就都要填单子,而不能乱哄哄的大家一起进去拿了就跑线程也是这样,A在放入队列,多个B在取出的时候,都要加lock,保证一次只有一个线程去操作队列B取出一个,就从队列里删除掉,让其他线程不会再取到一个同样的数据至于保证顺序,你可以让A在插入队列的时候加一个时间戳,B都处理完之后,按时间戳排序,就能够还原顺序还是出入库,如果箱子连个编号都没有,那么大家一起搬,有人搬的快,有人搬的慢,就没办法还原箱子原来堆放的顺序但是如果箱子有编号,就可以按原来的顺序重新堆放
解决方案:
我也遇到这个问题了,A方法需要频繁调用(A方法中也需要调用到B方法,B方法也需要用A方法的一些参数,B方法主要是用来界面显示处理数据的),B方法处理时间比较慢,调用A方法时需要等待B方法调用完,在此期间界面就进入假死了,频繁调用A方法时可以取最后一次A方法的参数,我想要的就是如何解决,调用B方法界面会进入假死的状态!