先来看看本来的体系界面是如何子的:
其功用如下,我新写的客户端增加了支持生成OCX控件的功用:
全部体系的物理架构是这样的:
跟着界面数量的增加,会需求更多的加载时刻
跟着地址和设备的增加,加载会需求更多的时刻
咱们来看看经过一些啥办法能够处理本来的体系存在的这些疑问。
大多数的状况下,咱们本来所能看到的东西都是极端有限的,不管体系是多么巨大,功用多么的丰厚,本来呈现给用户的都是极端有限的。
前面说了,监控主界面里的界面都是组态的,是由工程师拖拉控件上去完结的,咱们也看到上面图形还算丰厚,主要是运用了许多的图像,因而咱们体系中在保留这些组态界面的时分,一同也保留了界面图像的字节省。大型的数据中心由于界面较多,这些界面加起来是也许会超越1G巨细的。这么大的界面,假如都是直接加载到界面中,首要就要费不少的时刻,即便是在内网的状况下,假定你网络能够1s下载20M摆布,也要50秒,接近1分钟,遇上网络顶峰,花个1~2分钟并不奇怪。
咱们是不是有必要把一切界面都加载进来呢,当然没有。咱们只需加载第一个界面,其他界面在需求的时分(用户点击或许发作告警需求跳转的时分)才加载,这样咱们的速度里边就提高了,这即是按需加载!
当然说的轻盈,实践做的会有许多疑问。比方,如何完结不完结页面又能晓得该页面是不是告警(有必要解析每个界面上的控件,才干晓得某个界面包含了哪些控件,才晓得监控目标告警在哪个界面上)?
我的进程如下:
做监控体系,除了告警页面有必要实时告诉到客野外,监控数据界面,本来只需展示当时显现页面的数据即可。
如何做呢,咱们能够供给一个独自的程序来办理一切接收到的数据,然后再供给一个获取当时数据的接口给客户端,具体请看下面更改的架构。
有些人也许会疑问,为何不直接在采集器中供给这个接口呢?由于这是组态界面,界面上的控件要取哪个采集器的数据是未知的,所以把数据放在一同统一办理会愈加便利。并且采集器能够7*24小时作业,而客户端是常常要翻开封闭的……
假如用过VS2010开发自定义的Winform组件,那么咱们对它的工具箱加载自定义组件这个功用必定形象深入,每次挑选增加项,然后挑选自定义控件dll的时分,都十分苦楚,特别我电脑比照忙而又装了不少插件的状况下,为了一个十分简略的功用,我需求花费4分多的时刻来翻开那个挑选文件的界面,这个界面加载了一大堆我绝大多数时分都用不上的COM组件,我真实无法幻想开发这个功用的程序猿是如何想的。还好,在VS2013中微软总算是改进了这个功用,可是做得还不行。按我的主意,彻底能够把COM组件部分异步加载,给出正在加载的提示即可,能够当即显现“挑选”按钮,这样领会性当即上升了一个层次。
推迟加载是指用到的时分,再去进行实践的构建。
树形菜单的树形节点的构建即是一个最适合解说的比如。咱们能够测验加载1000个树形节点然后构建成一棵树,看看在Winform中需求多长的时刻。咱们的实践中有没有必要这么去做呢?
各位能够思考下自个检查树形导航的时分,是不是从根节点到子节点终究到叶子节点这样一步步看下去的,大多数的时分,本来咱们只需首要看到根节点即可。例如下面这个:
关于这种状况,咱们彻底能够把树形节点都获取,可是先只创立只要根节点的一棵树,在用户点击以后加载子节点,假如已判别过,则不履行加载的操作。底子的办法是在Tag中附加一个字段指示子节点是不是现已加载,参阅代码如下:
private void TreeDevices_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
var myNode = e.Node.Tag as NTier.Model.MyTreeNode;
if (myNode == null) return;
if (myNode.IsSubNodeLoaded == false)
{
//还没有加载数据,主要是指机房节点
LoadNodesOfSubMainForm(e.Node, myNode); //加载树形子节点
}
//已加载了数据,则生成相应的界面
LoadFormModel(myNode);
}
|
这儿推迟加载与按需加载有点相似,区别是,推迟加载有必要把一切数据加载进来,可是并不构建成一棵UI树,而是在用到的时分再去生成。
另一个当地即是每个控件的右键菜单。由于每个右键菜单显现的内容是需求依据控件的类型以及有关的权限来判别的,可是咱们看到右键菜单的时分一定是人为进行操作才干显现出来,因而没有必要再界面生成的进程中去为每个控件生成对应的右键菜单,而是在弹出右键菜单时进行有关的判别,推迟右键菜单的生成。
咱们晓得,假如要检查一棵树的一切节点,常用的办法即是运用递归进行广度遍历或许深度遍历。可是,在树形节点较多的时分,遍历本来是十分耗时的。在咱们这个体系中,告警是有必要要最早处理的,因而,我在体系中运用Dictionary类型缓存了每个特点节点与它有关联的数据类型(ID),然后能够在发作告警时立刻定位到指定树形节点。
咱们体系是组态的界面,这就约束了界面的生成有必要是动态的。假如咱们选用按需加载的办法,那么界面的生成即是实时的,如何能够做到疾速的进行页面的切换呢?
var tempPanel = _panelCache.CreatePanel(this, formModel, myNode.AgentBm); //创立Panel
|
在这儿,我专门写了一个界面的缓存类,假如没有缓存,则动态创立,假如有缓存,就直接回来缓存的界面。一同,依据界面的最新的翻开时刻和点击次数,对缓存的界面进行办理。咱们晓得,全部大型体系中,本来用户重视的界面也是有限的,通常他们只会重视最重要的几个界面,最常用的也是这几个界面。经过缓存的办理,不但能够完结界面之间的疾速切换,一同也减少了体系占用的内存。我全部客户端程序文件巨细紧缩以后在500k以内,而运转期间占用内存底子维持在50M摆布。
检查上面改造过后的架构,咱们晓得如今获取数据是在翻开界面以后再去获取,直到树立衔接并获得数据以后,才干在界面上显现,这个进程通常会耗时1~2秒,网络差的状况会更糟。如何才干让用户更为疾速的断定咱们的体系现已运转了呢?这儿咱们经过一个简略的办法,集中服务端经过守时把当时监控到的数据写入控件的特点中,在体系加载控件的一同把这个值显现出来,这样能够看起来好像是体系立刻获取到了数据。而由于缓存的值是守时把最新值写入进入的,这种做法在很大程度上保证了缓存中的数值是准确的。
异步是进步程序响应和用户领会的不贰法宝。C#中的控件和大多数流操作类等都供给了支持异步操作的办法:BeginXXX和EndXXX.它的原理也十分简略,运用BeginXXX时,把操作参加线程池,履行完结以后调用一个回调函数。
一个用户领会杰出的体系,应当能够合理的运用异步操作,保证履行UI更新时以及履行耗时的操作时不会堵塞。大多数人在写代码的时分,老是直接进行调用,在控件较少或许完结简略使命的时分,你通常都感受不出来,可是在控件数量多的时分,咱们很简略就感受到界面卡,不流通。
我在新体系开发的时分,就有认识的在控件加载、控件数据改写、控件告警状况切换等操作中运用了异步的操作,让体系在翻开界面时彻底感受不到卡的迹象。
不过运用异步要时刻记住,异步能够进步用户领会性,可是不会有性能上的本质提高,假如感受到数据响应有推迟,你仍是得花功夫找到底子的缘由。
咱们来看看本来界面是如何改写数据的:
翻开界面->改写数据->新建一个线程->守时改写数据->封闭界面->封闭线程。
对Windows体系有满足了解的人都晓得,新开一个线程都是十分消耗资本的。这种状况,咱们是能够在全部体系中,供给一个统一办理的改写线程,只需对当时需求改写的界面进行改写即可:
改写线程->判别当时界面是不是存在->守时改写数据
联系上述的异步操作,咱们的控件在改写数据的时分十分的流通。
上面咱们提到了,在体系发作告警时,有必要要跳转到报警的页面,这个机制在许多告警并发的时分,就会有十分大的疑问,很也许咱们的体系就会在不一样的界面中进行跳转而卡死。关于体系的用户来说,在1~3秒内的多个告警,咱们本来能够处理为一个告警,咱们只需往终究一个告警发作的页面跳转即可,这样既达到了相应的作用,也减少了体系的压力。这即是告警并发时的归并处理。
在一些状况中,咱们确实短时刻没有办法对性能进行提高了,花费的时刻却要要这么多,这种状况下,咱们有些啥好的做法呢?
假如咱们常常用手机登入微博、微信等,必定对这些app加载图像有过一些领会,特别假如你是在网络较差的状况下,同样是要等1分钟才干加载出图像,假如这个app没有任何提示,那么,过了30秒或许20秒,你就有也许受不了把他点掉了,由于你感受它好像现已过了几分钟,还有也许遥遥无期;而假如这个app能够提示当时下载的字节数、当时下载的进展,那么,1分钟的等候,你好像也能承受,这毕竟是网络致使的疑问。这即是一种视觉上的诈骗。
在一个体系的加载进程中,有提示信息和没FF;"> �提示信息,有进展条和没进展条,给人感受的速度是不一样的,即便从实践的状况来看这两者没有任何不同。
许多时分,咱们体系的运转需求从服务器中获取一些最新的数据,以支持底子的运转。这部分时刻是你必不可少的,许多人都认为这是没有任何办法��;"> �98化的,本来不然。咱们许多程序本来都供给了一个用户名和暗码的输入框,本来在用户输入的进程中,咱们仍是能够运用的。在弹出登入窗到输入账号和暗码到登入体系的进程中,通常都会有3~5秒的时刻。
我看到许多人写程序,弹出登录框就老老实实的弹出,然后在输入完用户名和暗码以后在进行数据的获取和加载�F;"> �F��实践上,咱们现已浪费了这些时刻。假如你能有用运用这3~5秒,那么,你就现已赢在了起跑线。
视觉诈骗的别的一个重要运用,即是在曲线的烘托中。在机房监控中,咱们有些设备的监控比照频频,一天发生的数据高达几万条,把这么多的数据制作到一条24小�F;"> �6��的曲线上,咱们将会看到许多鳞次栉比的点,制作这些点十分的耗时和耗资本。而咱们供给曲线给用户检查的意图是啥呢,是想检查一天的趋势变化,过多密布的点本来是没有必要的,咱们看看下图,假如数据点更多的话,第二个曲线会愈加密布,看起来会像一条粗大的直线:
经过简略算法对曲线进行紧缩以后,显现前史趋势的速度十分的快,十分的流通。咱们比照上面两条曲线,本来对用户来说,或许更喜爱第一条曲线,由于他反响的趋势更为优美,有木有?
在我的博文中,我一向着重运用单元测验,不管是开发仍是重构。我觉得这个不管是如何着重都不为过的。
在开发的进程,咱们应当有认识的按单元测验的意图来构建咱们的函数、类、以及程序集,假如你的函数契合单元测验需求的话,通常都是比照简略重构和维护的。别的,咱们开发的进程中,许多时分需求验证某个功用是不是可用,运用单元测验,将会很疾速的帮你完结这个验证操作。我看咱们许多程序员开发功率都不高,特别在开发一个大型体系的时分,喜爱把全部体系开起来调试,或许是在体系里边加上各种装备或许条件编译来进行调试,这种习气十分欠好。在程序中参加装备简略让程序结构呈现紊乱,代码的阅览领会也欠好,许多时分假如咱们忘掉去掉这个装备,很简略就对发布的体系发生较大的影响。
运用单元测验别的一个优点是,咱们能够随时针对某个办法进行性能上的测验,发现哪些代码对咱们的体系造成了较大的影响。我习气连私有的函数也一同参加测验,以下是调用私有函数的一个辅佐办法:
public static object InvokePMethod(Type type, string methodName, object classInstance,object[] @params)
{
const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var methodInfo = type.GetMethod(methodName, flags);
var result = methodInfo.Invoke(classInstance, @params);
return result;
}
|
在平时的开发中,我一向跟我的搭档着重日志的重要性。信任有一定开发经历的都晓得在体系中写日志,可是,如何把日志写好,许多人都掌握不了。在这儿我提几点主张:
之前咱们的体系是自个完结的日志组件,我用C#重写时,引入了NLog日志组件,我觉得这个日志组件十分好用。别的,我还专门供给了一个UI界面的调试窗,以便实施工程师在现场调试的时分能够疾速定位疑问。
在实践运转的进程中,由于有杰出的日志信息,我很快能够排查许多的疑问,而大多数的疑问都是由于装备致使的。我一致跟研制的搭档着重,尽也许的不要信任现场工程师给你的判别,应当要现场工程师供给依据给你,而要供给啥样的依据,作为一个研制,你才是最明白的。好的日志体系应当能够依据日志信息精确的定位到疑问,在离线的状况下能够最大程度的反响当时体系的装备、运转状况、以及错误信息。
终究用C#重写的客户端在各方面变现都十分的好,体系十分稳定,全部体系进入在2s摆布,页面切换在1s摆布,最重要的是,客户端跟体系的巨细没有关系,习惯巨细的数据中心。咱们看看新老体系在加载进程中的一个比照:
很明显,经过上述办法进行一些优化以后,咱们的体系在各个进程都有了提高,并且经过异步、缓存、诈骗等办法让一些进程能够同步进行,大大加马上体系的加载和相应。
我希望经过这篇文章,把客户端优化的一些办法共享出来,供咱们参阅。这其间没有啥深邃的常识,也没有说要你有必要选用如何的编程言语,仅仅是经过一些简略的办法,并归纳应用,就能把一个体系的响应速度从4分钟提高到只需两秒。当然,咱们还有其他许多的办法,比方分布式……不管是啥样的技巧,我觉得有一些底子的准则是要遵循的:
北京金恒智能系统工程技术有限责任公司 版权所有 Copyright 2007-2020 by Create-china.com.cn Inc. All rights reserved.
法律声明:未经许可,任何模仿本站模板、转载本站内容等行为者,本站保留追究其法律责任的权利!
电话:86+10-62104277/2248/4249 传真:86+10-62104193-819 京ICP备10010038号-2网站XML
智慧机房
在线体验