精华内容
下载资源
问答
  • 将时尚的互联网引入教学中来

    千次阅读 2011-12-19 18:04:07
    实际上,所谓这种负面的迷恋网络,是学生将很大一部分的时间用在了打网络游戏、看视频、聊天、经营空间等各种以娱乐为主的应用上。适度参加一些这样的活动,对学生来说是有益的。但是,过度使用只能造成各种各样的...
      在目前高校的教学工作中,有些同学迷恋网络,以致于影响了学习成绩。很多人将此归罪于网络,甚至有些学校做出大一新生不准购买计算机等的规定。实际上,所谓这种负面的迷恋网络,是指学生将很大一部分的时间用在了打网络游戏、看视频、聊天、经营空间等各种以娱乐为主的应用上。适度参加一些这样的活动,对学生来说是有益的。但是,过度使用只能造成各种各样的杯具。而如果将网络用在好的地方,不可否认其威力无比。
      再细究原因,学生为什么在购买计算机和联网时,目标是要用之于好好学习,但有了很好的条件后却背道而驰了呢?是因为他们没有能力在学习中使用网络,这需要有人帮助他们具有这种能力。确实,将网络用于学习,要比打游戏等难上手一些。将学生挡在网络之外,不是办法,不能因噎废食。相反的是,我们这些当老师的,应该将学生吸引到网络之中来,在教学环节中,引导及要求学生利用好互联网完成学习任务,让他们通过体验,有能力驾驭这匹烈马,并在长远的职业发展中,不断从领导世界发展的IT技术中吸取营养。
      教师主动地要求学生利用互联网,是与社会发展相适应的做法,是充分利用先进生产力的表现。如果对此怀有拒绝的心态,大多是教师没有跟得上形势,没有在自己的工作中利用好互联网造成的。青少年网络成瘾的一大原因在于家长对网络不了解,无法引导孩子正确使用网络。而如果高校教师在发展迅猛的互联网面前也不能先迈开一步的话,互联网在高等学校无法发挥正面作用,也就不足为奇了。因而,高校教师必须在这方面有所作为,主动了解这些应用,学会使用这些应用,并在教学设计中,将使用这些应用作为教学手段改革的重要着手点,大胆地利用起来。
      年青学生的好奇心强,热衷于各种新奇的事物。他们对新事物接受的速度和对此投入的热情远超我们这些所谓的“前辈”。这是我们可以利用的最大的资本,也是在有些方面失去控制的根本原因。如果教师利用好这股强大的动力,就一定能够获得丰硕的成果,营造出学生积极参与的良好局面。在教学中引入这些很潮的东西,学生会紧紧跟随,学习主动性大为增强,进而这些年青人也会向老师提出更炫的想法,将学习过程变得更加生动多彩。这不正是我们追求的教学氛围吗?
      将网络应用到教学中的手段包括(仅我写作时随意想到的):下载学习资料、登录论坛交流、利用数字图书馆、在线观看教学视频(如很火的网易公开课)、利用文档共享工具(如GoogleDoc)合作完成任务等。
      在本文中,先将我在下学期即将要试点的两个想法进行阐述,同时也帮助我理清工作的思路。两个想法主要在C++程序设计课程中使用,在试点基础上,我将进一步总结向其他课程中推广的手段。这两个想法分别是:(1)利用博客交作业;(2)利用微博进行答疑。看了此文有想法的老师(无论在何处),可以和我一起交流,探讨并实践这些想法,对此感兴趣的学生(无论何校,学习哪门课程),也可以参与进来。
      
    用博客交作业
      想法起源于我关注了我的几位学生的博客。他们是学习很主动、积极的同学,经常将自己课外学习的体会、成果放到博客上去,甚至有时放的就是某课程的作业或实验报告。从这些博文中,我看出了他们的成就感,看出了学习的快乐,看出了他们的自信,看出了他们不断陷入各种迷惘而又胜利突围的过程,也看到了他们学有所成的未来。于是我想到,为什么不引导我的学生都找到这种感觉呢?参与的人越多,我们这个群体的成就将会呈指数级增长。
      我开博已经有六年时间,真正将自己的博客定位于关注理想教育和美好生活,坚持写原创博文也已经有三年的时间。对写博的意义已经有了很深的感受。C++课程的第一次实验,我将指导学生建自己的博客,自豪地向全世界宣布“我来了”,将自己写的第一个程序写成博文。
      先给出用博客交作业的理由:
      (1)帮助学生驶入利用网络学习的“正”道:写过博文,就会经常惦记着往上加点东西,这是很有成就感的事。但万事开头难,于是有很多博主只成天转载别人的文章,没有原创。我将要求学生(必须)每周将实验报告发布为博文,我对实验的评分将以博文为依据;建议学生将课程的其他作业,尤其是调试过的程序也写晒到博客上,也许可以用加分作为诱饵。学生的原创博文就这样出炉了,并且每周至少一篇。以我的经历,一旦开写,一发而不可收拾。逐渐地,上论坛、看公开课,都是自然而然的了。会走正道,“歪”道就会少走,甚至不走了。
      (2)减轻学生和和教师的负担:我将设计一个实验报告模板,实验报告中大家全一样的文字学生不用再写,只将编好的程序、运行结果及总结写入,当堂完成并提交。我也会制作一个学生博客的清单,只要在课后一个个地打开、登记即可。如果需要点评一下,有“评论”呢,用博客干这个很得手。不出意外,我将抢占不少“沙发”。
      (3)避免抄袭:有人会问,往博客上一发,全世界都知道了,这不是更利于抄袭吗?似乎是这样的。实际上,防止抄袭是个世界性难题,又防又堵,不见得有效。换个角度想,抄袭是防不住的,但如果资源充足,由原先不方便看,偷偷摸摸地抄,变为让学生很方便地多看“几家”,比一比,想一想,也能改改成了自己的。由一贯的偷着抄,到合情合理地借鉴着抄,是个进步,其实这也是一种学习的正常方式。写到这儿,我想到了开源软件,其核心就是“不怕抄”和“坦然面对抄”。再者,每个人都有个脸面的问题,在博客中抄作业,让全世界都看到(起码全班同学都能看到),总是不愿意的。管着不让抄他要抄,放开了倒不一定这样了。至少我想碰碰这个运气。(这儿还有些想法,见后文。)
      (4)避免学生拖延:学生必须当堂调试并完成题目,实验课结束之后,最多拖延几小时后,我就会批改,哪用课代表一摧二摧也收不起来。人性化些的做法,实在交晚了,学生要单独打招呼请老师补批。目前学生与老师交流少,更大的原因是学生不会主动找老师(有人讲有考试完主动找老师的,我多年没有遇到过了,但更愿意学生在学习过程中主动找我。其中原因很复杂,但总得找个办法突破),这不就创造条件让学生体验主动找老师的感觉了吗?老找老师总不好意思,除了人人不可避免的客观原因,学生将尽力按时完成。于是,老师们成天强调的实验课前一定要做好准备,但总有人去了实验室才想要做什么事情的局面会有所改善。可以给每个学生只3次(或5次)的宽恕机会,总拖延是不对的,那扣分没商量。在这个过程中,还可以及时发现学习困难的学生,从而有了重点帮扶的对象。这又是传统教学方式中的一个难题。
      (5)增加交流与讨论:以博客为代表的Web2.0擅长的就是交流。作业放在博客上了,人人可以评论几句。对每个同学而言,都能得到更多人的指点,也能得到更多指点人的机会。不是说现在的学生们不爱交流吗?上网写点这些评语他们还是愿意的。如果这个群体干的事情能够引起高年级或外界高手的注意,不时来点拨一下那就更得益了。条件成熟时,我可以开发一个应用,统计每名同学在班级其他同学的作业博文中的留言,小小的个位数加分,将激起同学更多的热情。
      (6)学生的热情投入:人做一件事情难得的是兴趣。看多了太多的学生声称对专业不感兴趣,实则是在专业入门之时就难以投入。不管是出于老师施加的要求,还是在用时尚的工具玩学习的驱使,我在等着看热火朝天的局面。我不敢期望百分之百的学生,起码要高出现在传统方式很多比例的同学,专业学习热情会由此点燃。一旦学生入手做这件事情,除了我布置的题目,他们会利用这个平台表达、思考、沟通,找到互联网中更多的奇珍异宝,并从中收获。我将设计几个等级的作业,学生完成课程的基本要求之余,将会不为成绩,只为心中的梦想和那么一点点光荣的成就感,将进阶题目不断地做下去,发出来。
      这种方式存在的障碍(或负面影响)和应对办法:
      (1)学生抄袭:抄袭是这个方式最大的隐患。与其挡不住,不如提供更好的条件方便学生抄。但抄一定是不对的,会面临风险。老贺也定将与广大同学一起,与此不良风气展开坚决斗争。一经发现抄袭,除留言向全世界曝光之外,记零分甚至记负分是必不可少的。相信老贺有这样的狠心做这种狠事。也要组织好学习小组,帮助学习确实困难者不抄就可以完成任务(我相信抄袭最根本的原因是学生真的不会)。另外,咱是有技术背景的,现在我已经勾勒出来了针对用博客交作业这一应用的抄袭判定软件的基本需求和解决方案,无论直接用搜索引擎和文本处理技术,还是用博客提供的API接口,找出近似度高的作业版本,都是不难解决的。每次的博客作业总结中,可以出一份相似度判定清单,常居上之人,即使不受惩罚,也应该就不好意思了。这个应用有时间我自己做,或找高年级的学生做,都可以。除了在作业中搜索相同或相近版本,甚至可以开发出专门的应用,方便学生找不同版本进行参考,还鼓励学生多看几家了。可以将这个应用作为案例讲给学生,有了这种就在身边有实在体会的案例,学生将对搜索引擎和文本处理这两个热门领域了解一二,知道学计算机的人可以干这个事情。
      (2)学生需要有额外的经费支出。发博客得上外网,且学生的第一个博客我一定要让他选择最好的、影响最大的平台,那一定是外网了。所以学生必须每个月都花5元钱购买外网的使用费。和其他花费相比,这个数额不大,但有些同学在意,可以两三人共用一个帐号。我非常愿意看到学生们都有校园网出外网的帐号,上网上机都到计算中心。计算中心最便宜,有些机房的机器是有些旧,但作为学习来讲足够用了,唯一的缺点是打游戏的条件和氛围不是一般的差。前些天媒体曝光学校内有通宵打游戏的机房,学校很尴尬,同学很受害,我推荐同学上机就到计算中心。包月的上外网帐号可能会成为到计算中心上机的一个理由。
      (3)在这种模式下,现有的参考和指导材料缺乏。这没有什么,我将与我的学生并肩作战,一起建设。
      用博客交作业的方式即将开始试点,我也将面对新的挑战。这种方式可能并不适合所有课程。我非常害怕我的学生用这种方式衡量所有的课程及其他的老师。其实适合的才是最好的,这是一个基本观点。例如高等数学课,用作业本手写的方式应该是最好的。英语课的作文可能适合这种方式,如果上机方便的话。大部分的计算机软件类课程可能适合用这种方式。C++程序设计课程中使用这种方式最得天独厚的条件是有大量的上机时间,每一道作业只有上机调试后才算是结束,以此发博文只是顺手而为。
      
    用微博答疑
      我玩微博有半年多的时间了。微博很好玩,我只关注我感兴趣的人,从来不为增加粉丝数量而与人互粉,于是我在平时看到的微博文中,只是我的学生的发言,以及热心教育事业的几位博友的动态。周六乘车,看了李开复的新作《微博改变一切》,得到了对微博更全面的认识。我突然意识到,可以将我的学生引入微博的世界中来,将他们引入与合适的人交流、交流合适的话题的世界中来。学生需要走入这种时尚的,将改变一切的世界的应用中来,他们一定也会为自己及时跟上“潮”流而自豪。
      借助微博,我在教学中可以做些什么?答疑。现实中的答疑问题不少:时间不好统一,定好的时间老师去了,学生没有;对老师车轮战,老师顾不过来,有的同学没有机会;有了问题老师不在,见了老师忘了问题,或者没有了感觉。
      用微博答疑的好处在于:(1)随时可以将问题发出去;(2)能够得到除了老师之外的更多人的回答;(3)并非马上有人会回复和评论你的话题,这留下了更多的独立思考的机会;(4)大家(师生)可以在自己合适的时间处理这些事情;(5)有更多的学生可以参与到答疑中来,减轻老师的负担,增加同学锻练的机会,营造出学习型的组织;(6)140字的限制,利于提问者和答问者学会用有限的篇幅表达清楚,这种能力很重要;(7)字数限制,也有利于提问者和答问者的慎密思维。
      唯一想到的不利条件在于学生需要有很方便的上网条件。其实现在的大学生都有手机,手机上网的也占多数。发条微博几十秒的事情,手机足可以解决。这会不会鼓励让学生上课时都上网呢?还是那个观点,对堵不住的事情,就不要堵了,而是想办法引导学生用好。现在上课时看手机的学生不算稀少,多数在看电子书,或发短信,或用QQ。如果他们上网是在搜索对老师的某观点的质疑,或是发出一条微博表达自己的一个疑惑或心得,那不就是好事了吗?我倒是希望在我的课堂上,我在那儿叨叨,我的学生把着手机做着课程的现场直播,甚至我也拿出手机参与进去了。
      与Email相比,微博不是一对一的,可以让更多的人参与进来。以前用Email给学生解答了不少问题,想到有些问题具有共性,常常征得同学同意后再整理成博文等发布,花时间不少,但可能真正需要的人也看不到。再就是问者罗嗦,答者也不惜墨,洋洋洒洒,倒是写得不少,哪有微博精炼。当然,若有私密问题,Email是最好的途径。
      我非常反对学生以学习的名义使用QQ等即时工具,至于拿手机挂QQ更不可取。我是QQ声一响,就无法安心工作的人,相信大多人也有这样的体会,但一直放不下。实际上,大学生在学习中,要沉下心来,没有必要这样随时联系到,宝贵的大段时间就会被QQ拆散。我的工作也是这样。微博是面向大众的短信,利用碎片的时间看一看足矣,如课间、饭后,甚至到饭馆中点了盖浇饭等饭的那一点点时间。
      人人网等虚拟社区我没有用过,自是不敢玩的太深。仅有的映像是,人人网重在维护一个熟人的圈子,谈些熟人之间才能讲的事,多些家常里短,而微博更多靠相同的兴趣聚集。说不来太多,但总感觉人人网类似老同学坐到一起拉拉家常,微博则是志趣相投者能够各抒己见。要用于教学,后者更合适。
      微博答疑和博客交作业相比,博客是正面战场,而微博则可以补充点点滴滴,并且在学习中增添更多乐趣,让学习变得更加生动。
      现在学校已经建设了BB等专业的教学平台,在教学材料展示,学生留言等方面给了更多支持。我认为在教学中应该多利用免费的公用平台,像新浪博客、微博等。其一,公用平台紧跟时代潮流,更吸引人,更被年轻人喜欢,也让学生在学习中更加适应技术、社会发展的需要;其二,利用公共平台的开放性,使学生有机会接触到业界中的高手,接受生产一线的高人指点,主要靠教师建设的BB平台,自然是封闭且全面落败的了。以后在使用BB平台时,也只注重展示一些不便公开的一些私有资料为主。

      写完这一长段的文字,思路也逐渐明确。要将这些一一落实下来,还需要结合教学内容下一番苦功准备。到教学工作真正展开之时,至少是在我初探之时,必将耗费更多精力。但这毕竟是一件很有意思的事情,也有望得到好的教学效果。李开复给女儿描述自己的工作时说:“我每天的工作就是写Email。”有一天,我可能会告诉别人:“我每天的工作就是写博文、回微博。”
      那是相当的酷。

    注:这篇文章原于2011年6月28日发在我的新浪博客上,原文见http://blog.sina.com.cn/s/blog_5717f02f0100u3mv.html。随着一些实践的展开(见我的CSDN博客首页),已经有了更多的体会。我已经将自己的教学博文全部转移到CSDN,我的学生们正在忙于考试,下学期他们也将转战到CSDN。想起这是一系列工作的源头,转过来,和学生们共勉。
    展开全文
  • Cache层次结构的引入

    千次阅读 2015-05-10 10:29:25
    我经常尝试一些方法,试图去解决在存储器...1975年,Moor将其定律修正为“晶体的数目每18月增加一倍,性能也将提高一倍”。这个定律在维持了相当长一段时间的正确性之后逐步失效。首先体现在性能提高一倍上,使用过多

    我经常尝试一些方法,试图去解决在存储器子系统存在的瓶颈问题,总会陷入长考。在我们所处的这个领域,这个时代,在不断涌现出一些新的变化。这些变化会我们之前历千辛万苦学得一些知识和理念荡然无存。这些变化不会依赖你的喜好而改变。

    1975年,Moor将其定律修正为“晶体管的数目每18月增加一倍,性能也将提高一倍”。这个定律在维持了相当长一段时间的正确性之后逐步失效。首先体现在性能提高一倍上,使用过多核编程的人不敢轻易地说用3个处理器一定能到达单处理器乘2的效果,不用说2个核。更多的领域和应用证明并正在不断证明“18个月性能提高一倍”不断着发生错误。

    晶体管的数目每18个月增加1倍也遭到了前所未有的挑战。IntelTick-Tick计划努力维护着摩尔定律最后的领地,也无法改变最后结果。从已知的几乎全部领域看,技术的发展是初期爆发而后逐步平缓,从更长的时间段上分析将呈对数增长。摩尔定律不会例外只会在一段时期适用。这段时光将是属于Intel和半导体界最美好的岁月。

    在不远的将来,相同的Die所容纳的晶体管数目将是有限的。在时光飞舞中,这个将来距离我们这个年代很近,因为永远尚不足够遥远。摩尔定律的失效近在咫尺,这个失效率先对目前云集在处理器领域的人群产生影响。

    传统意义的多核时代已经逐步结束。在半导体技术所依赖的基础领域发生重大的更新与变革之前,使用更多的晶体管资源扩大处理器数量并不可取。在设计多核处理器公司中工作的一些朋友经常和我提起,今年或者明年他们就可以集成更多的处理器内核向Intel发起挑战。我想和他们说以相同的DieIntel可以集成更多那样的处理器内核,集成256512或者更多的处理器内核对Intel都不是太大的难题。只是不知这样做的目的何在,很多应用甚至无法发挥4个或者8个内核的性能。

    即便不谈这些性能问题,我们讨论功耗问题。有很多许多工程师在这个领域中孜孜以求,默默耕耘着,针对功耗进行各类优化。很多工程师在做这件事情时,忽略了一些在其他领域中的基本常识,甚至是能量守恒定律。

    忽略这些常识的结果是所做努力最后灰飞烟灭。在处理器领域,完成一件事情可能由多个任务组成,各类降低功耗手段的出发点是在完成这件事情时,统筹考虑多个任务的执行过程,避免重复性的工作。

    从这个角度上看,微架构在Misprediction时,产生的重复执行操作是最大的功耗来源,还有在多个任务执行过程中,与当前任务执行无关的功能部件的开启等,这些都是具体的优化细节。围绕着处理器功耗优化,有许多需要作出努力的工作细节,需要更多的人来参与。只是再多的人也注定不够。截止到今天,处理器设计的出发点还是为了能够解决更多的应用,希望拥有更多Feature来怀抱天下。

    这种设计思路从处理器诞生的第一天开始,那个年代距今已经较为遥远。处理器及其相关应用领域的发展与革新是二战之后人类文明进步重要的源推动力。其他领域在可望不可及过程中产生的无限向往,使得几乎剩余的所有应用迅速向这一领域靠拢。也因此产生了通用处理器,使处理器更加聪明,更加通用。

    处理器系统正是这样逐步通用化。Intel是产生这种通用处理器的最典型和最庞大的厂商。而目前发生和正在发生的诸多事实表明这种通用化已经举步维艰,诸如Memory Wall,功耗居高不下这样的问题已经触及通用处理器是否能够继续发展的底线。

    越来越多的领域提出了应用为王这样的口号,本质上这是一个使处理器不再继续通用的口号。更多的领域需要属于自己的定制,不再完全继续依托通用处理器。在这些领域,通用处理器仅作为一个基本组成模块,更多的是适合这个领域的定制逻辑。

    处理器领域在经历了爆发式增长,快速增长后回归自然,使得处理器不再神秘,使得一些电子类产品的使用习惯正在进一步回归。苹果近期辉煌源自于此。Jobs再次来到苹果后只做了一件事情,使MP3更像MP3,电话更像电话,平板更像平板。苹果的成功在于Jobs使一个没有受到这些来自处理器领域的专业或者半专业人的影响之下,正常的使用这些设备。这不是创新,是回归自然。任何人,任何群体,任何公司都无法阻挡这股天然的力量。

    在此之前,任何一款电子类产品都自觉或者不自觉的受到了来自处理器领域的影响。许多设备,甚至是许多嵌入式设备亦无法幸免。原本就应该属于应用领域的设计并没有按照自身领域的特点设计,被来自通用处理器领域的想法左右。在过去的岁月中,那片领域曾经多次证明引入通用处理器观点后获得了巨大的成功。这种成功在某种程度上桎梏了观念,使更多的人容易忘记在应用领域中所真正应该的关注。

    这些固有的观念无法阻挡专用化时代的脚步。专用化和定制化已经出现在通用处理器领域中,比如在加密算法实现领域使用的专用引擎,用于图像处理的GPU等等。近期会出现更多的加速引擎,会进一步弱化通用处理器。可以说这种专用化和定制化时代已经来临,通用处理器所覆盖的范围会越来越小。

    从这个角度上说,Intel之忧不在功耗性能比没有超过ARMCortex系列处理器,而是离通用处理器日益远去的各类应用,继续坚持使用更加通用的处理器,以包含更多的应用会遭遇比Memory Wall更加牢不可破的Wall,迎接几乎必败的格局。如果ARM架构不是进一步为应用预留空间,去采用通用方法去左右这些应用,通用处理器所面临的困境将如期而至。

    在通用处理器领域中,ARM架构的成功是一个莫大的讽刺。在其成功背后,最主要的原因是在使用ARM的许多应用中,ARM微架构不是如想象中那样重要。我们可以简单列举出在使用ARM构架中最伟大的几类电子产品,其中哪怕有一个是因为单纯使用ARM架构而伟大。ARM公司的高明之处是轻架构而重应用,由环绕其总线组成的Ecosystem势不可挡,率先开启了专用化时代,ARM微架构不过是一个载体。

    进一步定制化不意味着通用处理器将很快退出历史舞台。对于某类应用,定制辅以通用处理器的组合将长期存在,这种场景之下,定制的与应用紧密结合的部分成为主角。较为理想的情况是95%的定制与5%的通用处理器。这有助于解决存储器Wall和功耗问题。在这种情况下,处理器将不会频繁访问主存储器,即使访问也是在5%的基础上,也不用担心功耗问题,因为只有5%的权重。

    这样的结果是不是将全部负担转移到了定制化部分。不用为此做太多担心,我反对使用通用处理器所做的某些应用,是基于处理器过于通用而产生了过多的不需要的存储器访问,引入了并不需要的功耗。贴近应用的定制无法做到不进行数据传递,也无法避免不消耗能量,但是能够将这种影响限制到最小的范围之内。附着在处理器系统上的操作系统,也会因为这些变化而改变。从通用性的角度上看,x86处理器和Windows操作属于一类产品,只是一个在处理器领域,一个在操作系统领域。这两个产品处于同一个困境中。

    在不久的将来也许会出现适用于通用部分的操作系统,这个操作系统与传统操作系统,如WindowsLinux,这些操作系统所做的工作较为类似,却在不断弱化,Linux进入到2.6内核之后,再无实质变化,这是通用操作系统所面临的同一个问题。另一个部分操作系统将与定制相关,也被称为应用类操作系统,这些操作系统将有很多种类。

    有人会问,既然你认为定制化的时代已经开启,为什么花如此气力在通用处理器的Cache中。因为他山之石可以攻玉。通用处理器的发展借鉴了很多领域的精华,在定制即将兴起的时代,不能忽略通用处理器的核心。定制化领域依然会从狭义广义Cache的设计思想中受益。Cache的核心是数据缓冲组织结构,通路连接方法,管理策略和各类算法,这些内容较为基础。世间万物,千变万变,基础内容的变化较为缓慢。

    使用定制会缓解通用处理器做遇到的各类瓶颈,而不是消除。主存储器的容量和延时的不断增加依然是客观存在的事实。通用处理器领域的解决方法是引入更多级别的Cache。多核处理器的进一步发展使得多级Cache间的组成结构异常复杂。

    在单处理器系统中,Cache Memory由多个层次组成。这些层次相互关联,相互依托,而为参天大树。底部由主存储器与外部存储器组成庞大的根系,其上由各类Cache和各类用于连接的Buffer,形成茂密的枝干。这些参天大树更通过各种类型的网络,或松或紧连接在一起,若小为林,夫广为森,煌煌立于天地,善能用之,攻坚强者莫之能胜。在一个ccNUMA处理器系统中,典型的Cache Memory层次结构如41所示。

    4.1 <wbr>Cache层次结构的引入

    不断增加的主存储器容量需要更大的Cache减少Miss Rate,使用一个很大的L1 Cache无法胜任这个工作,主存储器不仅在变大,访问延时也在逐步提高,进一步加大了指令流水线间的差距。单独一级Cache无法掩盖这个差距。提高Cache的访问延时与进一步扩大容量是一个Trade-Off。而且Cache容量越大,其访问延时也越大。

    这些现状使得在现代处理器系统中引入多级Cache成为必然。在没有从根本上解决存储器子系统存在的这些问题时,Cache级数会逐步提高,目前大多数中高端处理器都已经包含了L3 cache,大规模地使用L4 Cache并非遥不可及。

    Cache Memory层次结构的最顶端为微架构中包含的系统寄存器和各类Buffer,如与Data Cache连接的LSQ和与Instruction Cache连接的I-Cache Line Filling部件中的BufferFLC(First-Level Cache)指与微架构直接进行连接的Cache。在许多微架构中,FLCL1 Cache,而在有些微架构中,在L1 Cache之上,存在一级L0 Cache,此时这个L0 Cache即为FLC

    LLC指在处理器系统中与主存储器直接相连的Cache。在不同的处理器系统中,LLC所指对象迥异,有的处理器使用L2 Cache连接主存储器,此时L2 CacheLLC;有的使用L3 Cache,此时L3 CacheLLC。有些处理器系统中,使用L1 Cache连接其上的微架构,同时连接其下的主存储器,此时L1 CacheFLC的同时也为LLC

    MLC其上与FLC相连,其下与LLC相连。在一个复杂的处理器系统中,Cache Memory层次结构由L0~L3 CacheEDRAM组成,其中L0 Cache与微架构直接相连,而EDRAM与主存储器相连。此时L0 CacheFLCEDRAMLLC,而L1~L3 CacheMLCs

    在处理器系统中,不同级别的Cache所使用的设计原则并不类同。每一级Cache都有各自的主要任务,并不是简单的容量与延时的匹配关系。假设一个处理器系统中含有L1L2两级Cache。多数程序具有的TemporalSpatial Locality使得L1 CacheHit Rate非常高,即便L1 Cache只有4KB或者32KB。这使得在L2 Cache层面并不会看到过多的Miss[70],这使得L2 Cache层面的优化重点并不是匹配容量与延时,而且L1 CacheMiss Rate越低,L2 Cache的延时越无关紧要[70]

    这使得在绝大多数微架构中,对于L1 Cache的优化专注于提高Hit Time,在现代处理器中其范围在3~5Cycle之间,为了避免在这个Critical Path上虚实地址转换的开销,很多微架构,如Cortex A8/9Opteron,直接使用了Virtual Cache。在L2 Cache层面,其Cycle与容量比大于L1 Cache的对应比值。这些设计方法使得Cache Hierarchy的设计在与直接使用一级Cache的整体Miss Ratio等效时,提高了Hit Time这个重要的参数。

    在不同的微架构中,L1L2 Cache的关系可以是Inclusive也可以是Exclusive或者其他类型,如果是Exclusive关系,计算L2 Cache的有效容量需要累加L1 Cache的容量。在L2 Cache层面中,具有更多的时间,可以实现更多的Way Associatively进一步降低Miss Ratio

    在现代处理器中,这个L1L2 Cache通常是私有的。LLC的实现需要考虑多核共享的问题,除了继续关注Hit TimeMiss RatioMiss Penalty这些基本参数之外,需要重点考虑的是Scalability,由多核处理器引发的Bus Traffic等一系列问题。

    在一个大型处理器系统中,不同种类的Cache需要通过Cache Coherent Networking进行连接,组成一个复杂的ccNUMA处理器系统。这个Cache Coherent Networking可以采用多种拓扑结构,可以使用MESHn-Cube,也可以是简单的树状结构,环形结构。在整个ccNUMA处理器系统中,这个Cache Coherent Networking的搭建异常复杂。

    比这个Networking更难实现的是Cache间的一致性协议,这个一致性策略可以使用纯硬件,也可以使用软件Message方式实现。Cache每多引入一级,这个一致性协议愈难实现愈难验证。其间的耦合关系设计复杂度已经超出许多人的想象。

    Cache Hierarchy还与主存储器间有强的耦合关系,延时与带宽是两者间永恒的话题。在这个话题之后的功耗亦值得密切关注。在主存储器之下是外部存储器系统,包括SSD(Solid State Disk),磁盘阵列和其他低速存储器介质。外部存储器系统的复杂程度不但没有因为相对较低的速度而减弱,而且这种低速使得设计者有着更大的回旋余地,可以设计出远超过Cache层次结构使用的的复杂算法。如上文提及的LIRSClock-Pro页面替换算法。在这个领域没有什么算法是万能的,所有算法都有自身的适用范围。

    在讲述这些复杂的设计之前,我们需要从更加基本的内容开始,需要回顾存储器读写指令的执行过程,在微架构中使用的LSU部件是Cache Hierarchy设计的最顶端。在多数微架构中,LSUAGUALU协调工作实现存储器读写指令的发射与执行。

    展开全文
  • linux无名管道和有名管道

    万次阅读 多人点赞 2017-04-07 16:27:04
    只要两个进程中存在亲缘关系,这里的亲缘关系的是具有共同的祖先,都可以采用管道方式来进行通信)。  向管道中写入数据时 ,linux 将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入...

    1无名管道:管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。

        单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

        数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。(有点像队列哈)

    #include <unistd.h>
    int pipe(int fd[2])

        该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由 pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。

        向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

    注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

    2)有名管道:不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

    有名管道的创建

    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char * pathname, mode_t mode)

        该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如closereadwrite等等

    3)无名管道由一个在基本文件系统存储设备上的INODE,一个与其相连的内存INODE,两个打开文件控制块(分别对应管道的信息发送端和信息接收端)及其所属进程的描述信息来标识,在系统执行PIPEP)命令行之后生成。并在P[0]中返回管道的读通道打开文件描述等,在P[1]中返回管道的写通道打开文件描述符。从结构上看,无名管道没有文件路径名,不占用文件目录项,因此文件目录结构中的链表不适用于这种文件,它只是存在于打开文件结构中的一个临时文件,随其所依附的进程的生存而生存,当进程终止时,无名管道也随之消亡。

    送入管道的信息一旦被读进程取用就从管道中消失了,读写操作之间符合先进先出的队列原则。

        管道文件是进程间通信的工具,为了尽量少的占用系统存储资源,一般系统均将其限制为最大长度为4096PIPSIZ)字节的小型文件。当欲写入的消息超过4096字节时,就产生了读、写进程之间的同步问题。首先写操作查找PIPE文件中当前指针的偏移量F-OFFSET,然后从此位置开始尽量写入信息,当长度达到4096字节时,系统控制写进程进入睡眠状态,一直等待读进程取走全部信息时,文件长度指针置0,写进程才被唤醒继续工作。

        为防止多个进程同时读写一个管道文件而产生混乱,在管道文件的INODE标志字I-FLAY项中设置了ILOCK标志项,以设置软件锁的方式实现多进程间对管道文件的互斥使用。

    无名管道存在着如下两个严重的缺点

        第一,无名管道只能用于连接具有共同祖先的进程。

        第二,无名管道是依附进程而临时存在的。所以后来推出了一种无名管道的变种-有名管道,它常被称为FIFO。有名管道除继承了无名管道的所有特性优点之外,还屏弃了无名管道的两个缺点。

        首先,FIFO是一种永久性的机构,它具有普通的UNIX系统文件名。在系统下可利用MKNOD命令建立永久的管道,除非刻意删除它,否则它将一直保持在系统中。

    其次,正是由于有名管道以“文件名”来标识,所以只要事先约定某一特定文件名,那样所有知道该约定的服务进程,不论它们之间是否有亲属关系,都可以便利地利用管道进行通信。

        通过下面的命令可以创建一个命名管道:

    /etc/mknod pipe_name p 

        其中“pipe_name”是要创建的命名管道的名字,参数p必须出现在命名管道名字之后。 

        命名管道文件被创建后,一些进程就可以不断地将信息写入命名管道文件里,而另一些进程也可以不断地从命名管道文件中读取信息。对命名管道文件的读写操作是可以同时进行的。下面的例子显示命名管道的工作过程。

        进程ABC中运行的程序只是一条简单的echo命令,它们不断地把信息写入到命名管道文件/tmp/pipe1中。与此同时,程序中的“read msg”命令不断地从命名管道文件/tmp/pipe1中读取这些信息,从而实现这些进程间的信息交换。 

        程序执行时,首先创建命名管道文件,此时程序处于等待状态,直到ABC进程中某一个进程往命名管道中写入信息时,程序才继续往下执行。使用rm命令可以删除命名管道文件从而清除已设置的 命名管道。 

        下面是一个用于记录考勤的例子: 

        在主机上运行的程序/tmp/text产生命名管道/tmp/pipe1,并不断地从命名管道中读取信息送屏幕上显示。 

    /tmp/text程序:

    if [ ! -p /tmp/pipe1 ]
    then
      /etc/mknode /tmp/pipe1 p
    fi
    while :
    do
      read msg
      if [ “$msg" = “" ]
      then
    continue
      else
    echo “$msg"
      fi
    done < /tmp/pipe1

       在终端上运行的是雇员签到程序/tmp/text1。每个雇员在任何一台终端上键入自己的名字或代码,程序/tmp/text1将把这个名字连同当时的签到时间送入命名管道。

    /tmp/text1程序:

    tty=‘who am I | awk ‘{print $2}’’
    while :
    do
    echo “Enter your name: \c" > /dev/$tty
          read name
          today=‘date’
          echo “$name\t$today"
          done > /tmp/pipe1

    当雇员从终端上输入自己的姓名后,运行/tmp/text程序的主机将显示类似下面的结果: 

    wang Thu Jan 28 09:29:26 BTJ 1999
    he Thu Jan 28 09:29:26 BTJ 1999
    cheng Thu Jan 28 09:30:26 BTJ 1999
    zhang Thu Jan 28 09:31:26 BTJ 1999

    named pipes(命名管道)管道具有很好的使用灵活性,表现在:

       1) 既可用于本地,又可用于网络。

       2) 可以通过它的名称而被引用。

       3) 支持多客户机连接。

       4) 支持双向通信。

       5) 支持异步重叠I/O操作。

    不过,当前只有Windows NT,UNIX支持服务端的命名管道技术,win95/97/98等不支持。SQL Server等数据库就有named pipes的连接方式。

    (资料来源于互联网)


    ========================================================================================================

    ===========================================================================================================

    管道:

    管道是进程间通信的主要手段之一。一个管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构。根据管道的适用范围将其分为:无名管道和命名管道。

    ●无名管道

    主要用于父进程与子进程之间,或者两个兄弟进程之间。在linux系统中可以通过系统调用建立起一个单向的通信管道,且这种关系只能由父进程来建立。因此,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程负责往管道中写内容,而另一个从管道中读取。这种传输遵循“先入先出”(FIFO)的规则。

    ●命名管道

    命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个FIFO文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。虽然FIFO文件的inode节点在磁盘上,但是仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。

     

    实现机制:

    管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大一般为4K大小,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。

    \

    从原理上,管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程Process 1上(连接在Process 1上的两个箭头)。当fork复制进程的时候,会将这两个连接也复制到新的进程(Process 2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; Process 1关闭从PIPE来的输入连接,Process 2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE。

    \

    详细的管道创建过程如下图:

    \

    实现细节:

    在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。如下图

    \

    有两个 file 数据结构,但它们定义文件操作例程地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊操作。

     

    关于管道的读写

    管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。管道写函数通过将字节复制到 VFS 索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。

    当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:

    ·内存中有足够的空间可容纳所有要写入的数据;

    ·内存没有被读程序锁定。

    如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。

    管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

    Linux函数原型

    int pipe(int filedes[2]);

    filedes[0]用于读出数据,读取时必须关闭写入端,即close(filedes[1]);

    filedes[1]用于写入数据,写入时必须关闭读取端,即close(filedes[0])。

    程序实例:

    int main(void)
    {
        int n;
        int fd[2];
        pid_t pid;
        char line[MAXLINE];
       
        if(pipe(fd)  0){                 /* 先建立管道得到一对文件描述符 */
            exit(0);
        }
    
        if((pid = fork())  0)            /* 父进程把文件描述符复制给子进程 */
            exit(1);
        else if(pid > 0){                /* 父进程写 */
            close(fd[0]);                /* 关闭读描述符 */
            write(fd[1], "\nhello world\n", 14);
        }
        else{                            /* 子进程读 */
            close(fd[1]);                /* 关闭写端 */
            n = read(fd[0], line, MAXLINE);
            write(STDOUT_FILENO, line, n);
        }
    
        exit(0);
    }
    命名管道(named PIPE)

    由于基于fork机制,所以管道只能用于父进程和子进程之间,或者拥有相同祖先的两个子进程之间 (有亲缘关系的进程之间)。为了解决这一问题,Linux提供了FIFO方式连接进程。FIFO又叫做命名管道(named PIPE)。

    FIFO (First in, First out)为一种特殊的文件类型,它在文件系统中有对应的路径。当一个进程以读(r)的方式打开该文件,而另一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间建立管道,所以FIFO实际上也由内核管理,不与硬盘打交道。之所以叫FIFO,是因为管道本质上是一个先进先出的队列数据结构,最早放入的数据被最先读出来,从而保证信息交流的顺序。FIFO只是借用了文件系统(file system,命名管道是一种特殊类型的文件,因为Linux中所有事物都是文件,它在文件系统中以文件名的形式存在。)来为管道命名。写模式的进程向FIFO文件中写入,而读模式的进程从FIFO文件中读出。当删除FIFO文件时,管道连接也随之消失。FIFO的好处在于我们可以通过文件的路径来识别管道,从而让没有亲缘关系的进程之间建立连接

    函数原型:

    int mkfifo(const char *filename, mode_t mode);
    int mknode(const char *filename, mode_t mode | S_IFIFO, (dev_t) 0 );

    其中pathname是被创建的文件名称,mode表示将在该文件上设置的权限位和将被创建的文件类型(在此情况下为S_IFIFO),dev是当创建设备特殊文件时使用的一个值。因此,对于先进先出文件它的值为0。

    程序实例:

    int main()  
    {  
        int res = mkfifo("/tmp/my_fifo", 0777);  
        if (res == 0)  
        {  
            printf("FIFO created/n");  
        }  
         exit(EXIT_SUCCESS);  
    }  

    编译这个程序:

    gcc –o fifo1.c fifo

    运行这个程序:

    $ ./fifo1

    用ls命令查看所创建的管道

    $ ls -lF /tmp/my_fifo

    prwxr-xr-x 1 root root 0 05-08 20:10 /tmp/my_fifo|

    注意:ls命令的输出结果中的第一个字符为p,表示这是一个管道。最后的|符号是由ls命令的-F选项添加的,它也表示是这是一个管道。


    FIFO读写规则 

    从FIFO中读取数据:

    约定:如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作

    • (1)如果有进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞。对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。
    • (2)对于设置了阻塞标志的读操作说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。
    • (3)读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。
    • (4)如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。
    • 注:如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。


    向FIFO中写入数据:

    约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作

    对于设置了阻塞标志的写操作

    • (1)当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。
    • (2)当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

    对于没有设置阻塞标志的写操作

    • (1)当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写;
      • (2)当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。


    【参考】

    http://www.2cto.com/os/201607/528773.html

    http://www.cnblogs.com/mydomain/archive/2011/04/26/2029493.html


    展开全文
  • Angular深入理解管道Pipe

    万次阅读 2018-02-25 22:14:16
    纯变更的是,原始类型值(String,Number,Boolean,Symbol)的改变,或者对象引用的改变(对象值改变不是纯变更,不会执行). 非纯管道: Angular会在每个组件的变更检测周期执行非纯管道。所以,如果使用非纯...

    Angular深入理解管道

    管道的链接

    有学过linux shell的同学,应该知道管道,在shell中的管道是IPC,linux的进程间通讯有pipe,FIFO,signal。这里只是简单介绍一下,那么管道是做什么用的,在linux中是被用来进程间通信的,也就是传递信息,那么在angular中做什么用呢?答案是,用处有很多。

    管道分为两种。
    - 纯管道 Pure Pipe
    - 非纯管道 Impure Pipe

    默认情况下,管道都是纯的,在自定义管道的时候,如果把pure标志为false,就是非纯管道了。如:

    @Pipe({ 
      name: 'format'
      pure: false
    })

    纯管道和非纯管道的区别:
    - 纯管道:

    Angular只有检查到输入值发生纯变更时,才会执行纯管道。纯变更指的是,原始类型值(String,Number,Boolean,Symbol)的改变,或者对象引用的改变(对象值改变不是纯变更,不会执行).

    • 非纯管道:

    Angular会在每个组件的变更检测周期执行非纯管道。所以,如果使用非纯管道,我们就得注意性能问题了。

    纯管道与非纯管道区别的本质

    其实Angular官方给的解释很苍白,我在这里和大家介绍一下本质区别。 Angular为什么区分纯与不纯,原因是这里涉及函数式编程(FP)的思想,那么我们先来介绍一下,纯函数与非纯函数。

    Pure Function

    我认为纯函数就是一个没有内部状态的函数,也就是完全独立的函数。

    这意味着它执行的所有操作都不受状态的影响,给出相同的输入参数产生相同的确定性输出。

    举一个例子:

    // 不纯的
    var minimum = 21;
    
    var checkAge = function(age) {
      return age >= minimum; // 当minimum改变时,返回结果发生变化
    };
    
    // 纯的
    var checkAge = function(age) {
      var minimum = 21;
      return age >= minimum;
    };

    只有函数组合中的所有函数都是纯函数,我们组合起来的新函数才会是纯函数。

    Impure Function

    非纯函数那么就是函数的结果受外界的状态影响,即使输入相同的参数,也会返回不同的结果,例如如上面的。

    总结
    所以当纯管道就是意味着只有输入的参数发生变化的时候才会执行,而非纯管道是当angular的周期性检查时就会执行,这里稍微说一下,angular的周期性检查并不是”脏检查”,而是通过zone.js库。

    内置Pipe

    Angular内置了很多指令,这些指令大部分被用来格式化数据。管道可以将数据格式化显示,但是不改变源数据,所以是一个深复制,比如日期的显示。

    pipe使用

    和shell 语法一样,使用“|”来使用管道,格式为:

    {{ 输入数据 | 管道 : 管道参数 }}

    我们先来看一个例子吧。

    // app.component.ts文件
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      birthday = new Date(2018, 2, 25);
    }
    // app.component.html
    <h1>My App</h1>
    <p>My birthday is {{ birthday | date: "MM/dd/y" }}

    显示结果:

    My App
    My birthday is 03/25/2018

    使用就是这么简单,当然Angular为我们提供了很多的内置管道。这里我们要记住一点,所有的Angular内置管道,我们是不需要import的,直接就可以在.html模板内使用。

    管道 功能
    DatePipe 日期管道,格式化日期
    JsonPipe 将输入数据对象经过JSON.stringify()方法转换后输出对象的字符串
    UpperCasePipe 将文本所有小写字母转换成大写字母
    LowerCasePipe 将文本所有大写字母转换成小写字母
    DecimalPipe 将数值按特定的格式显示文本
    CurrentcyPipe 将数值进行货币格式化处理
    SlicePipe 将数组或者字符串裁剪成新子集
    PercentPipe 将数值转百分比格式

    接下来我们稍微讲一下使用方法:

    • JsonPipe
      JsonPipe管道通过JSON.stringify()来将输入数据对象转换成对象字符串
    // app.component.ts
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
       jsonObject: Object = {name: 'xiaoming', age: '35', family: {parent: 'vincent', mother: 'bella'}};
    }
    // app.component.html
    <h1>My App</h1>
    <pre>{{jsonObject | json}}</pre>

    显示结果:

    My App
    {
      "name": "xiaoming",
      "age": "35",
      "family": {
        "parent": "vincent",
        "mother": "bella"
      }
    }

    标签是一个格式化数据的标签。

    • UpperCasePipe
      大写转换。
    expression | uppercase
    • DecimalPipe
      DecimalPipe管道用于对数值的整数与小数部分按照指定规则进行格式化,这种格式化方式也成为本地格式化处理,语法如下:
    expression | number[:digitInfo]

    参数digitInfo的格式如下:

    {minIntegerDigits}.{minFractionDigits}-{maxfractionDigits}

    a. minIntegerDigits:整数部分保留最小的位数,默认值为1.
    b. minFractionDigits:小数部分保留最小的位数,默认值为0.
    c. maxFractionDigits:小数部分保留最大的位数,默认值为3.

    示例:

    // app.component.ts
    import { Component } from '@angular/core';
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      number = 0.4;
    }
    // app.component.html
    <h1>My App</h1>
    <p>{{ number | number: '3.1-2'}}</p>

    显示结果:

    My App
    000.4
    • PercentPipe
      PercentPipe管道可以对数值进行百分比处理。语法如下:
    expression | percent[: digitInfo]
    • SlicePipe
      SlicePipe管道用于裁剪数组或字符串,返回裁剪后的目标子集。语法如下:
    expression | slice: start[: end]

    SlicePipe是基于Array.prototype.slice()方法和String.prototype.slice()方法来实现的。
    - CurrencyPipe
    CurrentPipe管道可以将数值进行货币格式化处理。语法如下:

    expression | currency[: currencyCode[: symbolDisplay[: digitInfo]]]

    a. 数currentcyCode:表示要格式化的目标货币格式,值为ISO 4217货币码,如CNY人民币、USD美元、EUR欧元等。
    b. 参数symbolDisplay:表示以该类型货币的哪种格式显示,值为布尔值,true表示显示货币符号如¥、$等,false表示显示ISO 4217货币码如CNY、USD等。
    c. 参考DecimalPipe管道。

    自定义Pipe

    讲了这么多Angular的内置命令,当然这些远远是不够的,所以有时候我们是需要自定义管道来解决我们的需求。

    1. 命令行输入 ng g p sexReform
      Angular会为我们生成默认管道文件,真的很贴心啊~~~。我们来实现一个识别male展示为female展示为
    ```
    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
      name: 'sexReform',
      pure: true // 如果你的管道不受外界影响,只受参数的影响请遵守FP原则,设置为纯管道
    })
    export class SexReformPipe implements PipeTransform {
    
      transform(value: string, args?: any): string {
        switch (value) {
          case 'male': return '男';
          case 'female': return '女';
          default: return '不男不女或雌雄同体';
        }
      }
    }
    // app.component.ts文件
    import { Component } from '@angular/core';
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      sex = 'male';
    }
    // app.component.html模板
    <p> {{ sex | sexReform }}</p>
    <p class="{{ sex | sexReform }}"></p>

    注意我们使用管道的时候,需要在相应的*.module.ts内import进来。

    管道性能优化

    管道的使用需要注意一点的是Angular对管道的优化。我们来看例子:

    1.命令行输入 ng g p selectFilter

    // select-filter.pipe.ts
    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({
      name: 'selectFilter'
    })
    export class SelectFilterPipe implements PipeTransform {
    
        transform(allContacts: Array<any>, prefix: string) {
          return allContacts.filter(contact => contact.name.match('^' + prefix));
        }
    }

    然后在app.module.ts内import这个管道,一般angular会帮我们自动加入的。

    1. 新建组件 ng g c pipeDemo
    // pipe-demmo.component.ts
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-pipe-demo',
      templateUrl: './pipe-demo.component.html',
      styleUrls: ['./pipe-demo.component.css']
    })
    export class PipeDemoComponent {
    
      contacts = [{name: '张三'}, {name: '李四'}];
      addContact(name: string) {
          this.contacts.push({name});
      }
    }
    // pipe-demo.component.html
    <input type="text"
           #username (keyup.enter)="addContact(username.value)" placeholder="输入联系人后回车添加" 
    />
    <div *ngFor="let contact of (contacts | selectFilter: '李')">
       {{contact.name}}
    </div>

    然后在app.component.html中引入这个组件。

    当我们在input空间内输入一个以“李”开头的人名时,并不会刷新界面,原因是:

    <div *ngFor="let contact of (contacts | selectFilter: '李')">

    这段代码中的contacts是我们定义的数组,Angular监测体制并不会感受到他的变化,为什么呢?这是因为Angualr优化了管道的监测机制,它会忽略对象内值的变化,只会监测指向对象的指针是否发生改变。

    当我们把自定义的指令 pure属性设置false,Angualr就会识别出来,然后刷新界面。所以我们在使用的时候需要注意。

    展开全文
  • 长瘦管道的MSS对TCP性能的影响

    万次阅读 2016-08-14 11:03:25
    目前Linux采用的是方案2,其考虑的是,拆分一个整MSS带来的收益太小了,同时付出的代价却比较大,会在窗口边界打乱数据的规整性,事实上,如果网络时延(的是RTT)足够短,预期中Seg3的ACK会很快返回推动窗口向右边...
  • 1.引入本地jar包 在项目路径下面新建lib文件夹,并把jar包文件放到这个目录下 如: 2.在pom文件定义依赖并指向刚才引入的文件 如: &lt;dependency&gt; &lt;groupId&gt;org.taobao.sdk...
  • 晶体介绍工作原理与历史

    千次阅读 2018-01-12 10:52:20
    转载路径 ...与普通机械开关(如Relay、switch)不同,晶体利用电讯号来控制自身的开合,而且开关速度可以非常快,实验室中的切换速度可达100GHz以上。  晶体,本名是半导体三极管,是内部含有
  • Linux 管道(pipe)原理及使用

    千次阅读 2013-12-20 17:44:53
    当系统调度写任务执行时,如果写任务要写多个数据,那么当写指针到尾部时,本来缓冲区应该为满状态,不能再写,但是由于读指针处于非法位置,在读任务执行前,写任务会任务缓冲区为空,继续进行写操作,将覆盖还...
  • 第三方存业务基础知识

    万次阅读 2014-02-20 14:56:37
    2、为什么要引入客户资金第三方存? 2 3、《证券法》创立客户证券结算资金“第三方存”制度的意义? 3 4、实行“第三方存”对客户有什么好处? 3 5、券商实行“第三方存”后客户需要做什么? 3 6、三方...
  • Python 处理管道的方法

    万次阅读 2012-05-29 00:07:23
    Python 处理管道的方法 Linux下的可以施展的最炫的...我们想在程序中使用一个子程序,但是需要动态的传递参数(这里说的动态,是根据上次子程序输入的结果来决定这次输入什么),怎么办呢,不用慌,有subproc
  • Offer66题之每日6题 - 第五天

    万次阅读 2018-01-03 23:22:35
    来映射原结点和对应的新结点,刚开始的时候不要随机指针,按照没有随机指针来做,把 map 填上;这样搞完后,再遍历一遍新链表,利用 map 中的映射来确定随机指针,下面分别给出递归做法和非递归做法。 /* ...
  • 2.从晶体到“1+1=2” 2.1.晶体如何表示0和1 2.2.从晶体到门电路 2.3.从门电路到半加器 3.完成一次真正的计算 3.1.穿孔纸带 3.2.演练一番 3.3.编程语言的本质 1.理论先行 1.1.二进制思...
  • 通过前面的铺垫,现在我们应该知道,激活层存在的最大目的,莫过于引入非线性因素,以增加整个网络的表征能力。 这时,选取合适的“激活函数”就显得非常重要了。在前面的章节中,我们提到了常用的激活函数 ...
  • [Linux] 管道容量以及缓冲区的组成

    千次阅读 2016-07-28 10:15:51
    一.管道容量:管道容量分为pipi capacity 和 pipe_...而pipe capacity的是管道的最大值,即容量,是内核内存中的一个缓冲区。 pipe_buf: 命令:ulimit -a 在终端输入该命令就会出现如下一表: 管道容
  • 管道容量以及缓冲区的组成 (Linux)

    千次阅读 2016-07-03 00:25:50
    而pipe capacity的是管道的最大值,即容量,是内核内存中的一个缓冲区。 pipe_buf : 命令:ulimit -a 在终端输入该命令就会出现如下一表: 管道容量 sizeof(pipe_buf)= 512 bytes* 8 = 4kb pipi...
  • 而pipe capacity的是管道的最大值,即容量,是内核内存中的一个缓冲区 命名管道FIFO: 为了解决无名管道而引入的,与匿名管道类似,最大的区别是,有实体文件与之关联,由于存在实体文件,不相关的没有血缘关系的...
  • linux 管道(linux Pipe与named Pipe)

    千次阅读 2013-11-20 14:12:12
    当系统调度写任务执行时,如果写任务要写多个数据,那么当写指针到尾部时,本来缓冲区应该为满状态,不能再写,但是由于读指针处于非法位置,在读任务执行前,写任务会任务缓冲区为空,继续进行写操作,将覆盖还...
  • TVS选型详细流程

    千次阅读 2020-04-06 09:34:37
    (3) VBR 击穿电压 击穿电压,在 V-I 特性曲线上,在规定的脉冲直流电流IT或接近发生雪崩的电流条件下测得 TVS 两端的电压。测试的电流IT一般选取10mA左右,施加的电流的时间不应超过400ms,以免损坏器件,VBR MIN...
  • 5.揭秘angular2学习 ------- 管道

    千次阅读 2017-02-28 11:29:33
    //引入PipeTransform是为了继承transform方法 @Pipe({ name: 'sexReform' }) //name属性值惯用小驼峰是写法 export class SexReformPipe implements PipeTransform { transform(value: string): ...
  • 、托管、监管的区别

    千次阅读 2017-04-07 10:59:10
    但是又经常被平台宣传的存、托管、监管而弄得一头雾水,傻傻分不清楚。  那么何为存,托管及监管呢?字面意思及在P2P的含义又有何不同?  存  如果您投资过股票,您一定对“第三方存”并不陌生,
  • TVS: TVS超过它的耐压值后,会瞬间导通短路,反应速度在ns级, 而稳压是稳压作用的,超过它的稳压值,只要功率不超过它的耐受值,就会稳定在它的稳压值范围内。 TVS是瞬态抑制二极管,主要是用来抑制瞬时...
  • Jenkins REST API 使用

    万次阅读 2016-10-12 14:43:59
    其中,Stapler 技术的引入使得 Jenkins 可以自动为应用程序对象绑定 URL,并创建直观的 URL 层次结构。 所以,通过该项技术的引入,我们可以快速访问对应的Job及其相应资源。而这些资源包含的内容有哪些呢?可以说...
  • Python进程、线程和协程实战

    千次阅读 多人点赞 2020-12-09 21:01:13
    前些日子写过几篇关于线程和进程的文章,概要介绍了Python内置的线程模块(threading)和进程模块(multiprocessing)的使用方法,侧重点是线程间同步和进程间同步。随后,陆续收到了不少读者的私信,咨询进程、线程...
  • 城市排水管道系统设计计算的进展

    千次阅读 2004-07-15 02:00:00
     动态规划法是解决多阶段决策问题最优化的一种有效方法,无论是利用节点埋深还是利用段管径作为状态变量,并没有充足的证据能够证明阶段状态的“无后效性”(“无后效性”是当给定某一阶段的状态时,在以后各...
  • 上市之初的宇信易诚(NASDAQ:YTEC),曾经连续两年业绩增长速度超过...而上市数年间,多位高离职,带走了业务团队,带走了客户,这一切的背后到底发生了什么?又是什么成为矛盾激化的导火索?  两季度亏损359万美元
  • 花大量时间设计绩效考核系统,不仅没实现战略目标,反而引发了公司高的辞职和冲突
  • 底厂生系统改进方案

    千次阅读 2009-04-26 00:31:00
    引入周生产任务需求 , 日生产任务需求 现场生产按日计划的数量生产 , 而不是参照订单的出货交期来自由排产 . 只有这样才能赢得时间 , 使得各个制程的物流能同步 , 才能实现后拉时的 lean 生产方式 . u   通过...
  • 《剑Java面试-Offer直通车》--计算机网络

    千次阅读 多人点赞 2020-03-13 23:51:28
    计算机网络 网络基础知识讲解 OSI七层
  • 路径MTU的是当前在两个主机之间的路径上任何网络上的最小MTU。 IP中的路径MTU发现的实现:在IP首部中设置“不要分片(DF)”比特,来发现当前路径上的路由器是否需要对正在发送的IP数据报进行分片。如果一个待转发...
  • 其他就不需要了,因为所以相关工具插件全装好,但 babel 升级到版本6后,移除全家桶,将各工具拆分成单独模块,比如 babel-core 、 babel-cli 、 babel-node 、 babel-polyfill 等;并且新增了 .babelrc 配置文件...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 61,270
精华内容 24,508
关键字:

引入管是指