精华内容
下载资源
问答
  • 以下为《信息技术优化教学设计》的无排版文字预览,完整格式请下载下载前请仔细阅读文字预览以及下方图片预览。图片预览是什么样的,下载的文档就是什么样的。信息技术优化学科教学设计方案作业题目:结合您在本次...

    以下为《信息技术优化教学设计》的无排版文字预览,完整格式请下载

    下载前请仔细阅读文字预览以及下方图片预览。图片预览是什么样的,下载的文档就是什么样的。

    信息技术优化学科教学设计方案

    作业题目:

    结合您在本次培训中选定的课程,完成一篇教学设计方案,并作为终结性成果以作业形式提交。

    1.作业要求

    (1)必须是原创,抄袭将被判定为“不合格”。

    (2)要体现信息技术的应用;字数要求500字以上。

    (3)对于优秀作品,我们会进行整理并予以展示,请各位老师认真完成并学习其他学员提交的优秀作品。

    *请下载信息技术优化教学设计(模板)编写作业,为方便批改,建议先在文档编辑word软件里编辑好,再将内容复制到答题框提交,操作不要超过20分钟。

    2.成果模板

    (1)教学设计方案模板

    教学设计方案

    课题名称

    函数单调性

    姓名

    黄柏根

    工作单位

    休宁中学

    年级学科

    高一数学

    教材版本

    人教A版

    一、教学内容分析(简要说明课题来源、学习内容、知识结构图以及学习内容的重要性)

    “函数的单调性”是函数研究的重要内容之一,是在学生学习了函数概 念的基础上所研究的函数的第一个重要性质,它揭示了函数自变量与函数值之 间的数量变化规律,反映了函数图象的增、减性,体现了数形结合的数学思想, 是学生后面学习指数函数、对数函数、三角函数、不等式等重要知识的铺垫.函 数单调性是培养高一学生逻辑推理能力的重要素材,对提高学生的数学能力有 着重要影响

    二、教学目标(从学段课程标准中找到要求,并细化为本节课的具体要求,目标要明晰、具体、可操作,并说明本课题的重难点)

    培养学生由特殊到一般,由直观到抽象的抽象概括能力;

    通过函数单调性的证明,培养学生的逻辑推理能力;

    通过函数单调性的应用,培养学生的发散思维和创新精神。

    三、学习者特征分析(学生对预备知识的掌握了解情况,学生在新课的学习方法的掌握情况,如何设计预习)

    高一学生,他们的智力发展已到了形式运演阶段,具备了一定的抽象思维 能力和演绎推理能力,所以我在授课时注重引导、启发、研究和探讨以符合这 类学生的心理发展特点,从而促进思维能力的进一步发展。

    四、教学过程(设计本课的学习环节,明确各环节的子目标)

    (一)创设情境,形成概念;(二)发现问题,探求新知 用几何画析来指导学生观察自变量x(三)精讲范例,加深理解(四)强化训练,巩固双基 (五)小结归纳,拓展深化 (六)布置作业,提高升华.

    五、教学策略选择与信息技术融合的设计(针对学习流程,设计教与学方式的变革,配置学习资源和数字化工具,设计信息技术融合点)

    教师活动

    预设学生活动

    设计意图

    让学生观察多媒体演示一次函数和二次函数的图象,引导学生从左至右看 函数的图象是如何变换

    课上小组讨论归纳

    用 ppt 的形式把这个 问题提出来,让学生自己思考,讨论。

    用几何画板来指导学生观察自变量 x 的值由小到大 变化时,函数值 y 是如何变化的.

    体会图象法:函数图象是判断函数单调性的重要方法

    由直观到抽象的演变

    用多媒体课件探讨书本第29页的例1,引导学生看图,

    让学生自己先试图尝试证明单调性。开展自评和互评活动

    由被动接受知识到主观体验

    六、教学评价设计【创建量规,向学生展示他们将被如何评价(来自教师和小组其他成员的评价,也可以创建一个自我评价表,这样学生可以用它对自己的学习进行评价】

    1、是否认真专注 2、是否积极参与 3、是否独立思考 4、是否主动探索 5、能否自由表达 6、是否善于合作 7、是否敢于否定 8、是否兴趣浓厚

    七、教学板书(本节课的教学板书。如板书中含有特殊符号、图片等内容,为方便展示,可将板书以附件或图片形式上传。)

    1.课题引入

    2.单调性定义

    3.例题

    4.作业布置

    [全文已结束,注意以上仅为全文的文字预览,不包含图片和表格以及排版]

    以上为《信息技术优化教学设计》的无排版文字预览,完整格式请下载

    下载前请仔细阅读上面文字预览以及下方图片预览。图片预览是什么样的,下载的文档就是什么样的。

    展开全文
  • 热门技术强化

    2009-12-21 13:37:56
    需要学员们去深化的一些的技术如下: ajax:包括它的一些常用框架,如DWR,JQUERY等。这里面,ajax的框架学起来是非常简单的,应用学习最多不会超过三个小时,最主要的是要了解ajax的基本理论和它的应用范围。ajax...
    IT行业在深圳诞生已久,随着竞争的不断加强,经济的波动,大量IT企业/公司的不断涌现,很多中小型企业出现了接单难的现象,很多公司为了生计,不再单一的做一些产品,可以说接到什么做什么,这样一来,公司的技术、框架可能多元化,这样就需要程序员有技术的综合能力和不断学习的能力,与此同时,公司和企业对待技术人才的要求也不断的提高。
    
    就JAVA来讲,我就业中心虽然挑选了占据该领域大部分分额的SSH三层框架和常用的SQLSERVER、oracle做为学员就业时的必备技能,但是从技术角度和公司的利益角度来考虑的话,这些还是不够的,而学员们没有要在这短短的时间内学习其他这么多技能的话,是不是难以应付。实践告诉我们,学员们或许并不需要对其他方方面面的技术技能都了如指掌,但最起码需要知道他们,这里面包括:专业术语,原理,应用范围,技术亮点的了解等。如果学员们在这短短的一个月之内认真的去准备和总结,做到这一点,也是很容易的。
    需要学员们去深化的一些的技术如下:
    ajax:包括它的一些常用框架,如DWR,JQUERY等。这里面,ajax的框架学起来是非常简单的,应用学习最多不会超过三个小时,最主要的是要了解ajax的基本理论和它的应用范围。ajax本身是多线程操作,在创建的两个对象上面做一些请求、响应事件,以XML为媒介进行前后台的及时交互。但是它不是线程安全的,比较耗费内存,所以尽量避免它的应用和线程安全的控制。
    hibernate的深入:hibernate的二级缓存处理(知道个大概就可以了)、多元数据库的配置、关系映射机制(例如,一对一,一对多等)、批量处理性能问题(hibernate在批量删除方面较弱)、框架中何时用jdbc更适合一些(例如:报表SQL脚本,批量删除,复杂的sql语句等用jdbc更好控制)。
    struts2:主要了解与struts1的差别问题(struts1是模仿webwork开发所得,strtus2彻底集程了webwork2所开发出来的,起内在原理都具有差异,struts1在view层与cotrol层的控制方面要求比较局限,而struts2在这个方面更为灵活,其理念就有所不同。)
    spring的深入:我们的学员仅知道spring的控制反转和面向切面,却不知道其内在含义,这是相当致命的弱点,必须将理论与实践联系起来,spring强大的功能不仅仅是这两个方面,要了解spring的源对象和我们new的对象有何不同,spring中还用到了单例、代理等工程的应用,而事物的控制也必须是一个重点,还有spring一个新的概念:JPA的理解。
    webwork:这个技术出现的比struts早,由于推广的弱势使之没落,其实webwork和struts1在应用方面极其相似,可以对照strtus1去看这个技术。
    工作流、jwt技术:这方面对于我们的学员而言比较难了,所以只需要去了解一下即可,其中jwt是工作流的一个制作工具,虽然jwt性能质量方面得到很多人人的认可,但是由于其的复杂程度较高,给软件开发过程带来了一定的风险,所以还不是最优选择,其实工作流的制作方法,方案很多,如今开源的jbpm甚为流行,只要知道即可。
    XML:我们学员虽然学习过相关的内容,但是很多人还是对他知之甚少。xml应用的范围主要是配置和网络传输,要知道为何用它来做配置?网络传输以xml方式有何优势等。webservice就是利用xml进行交互的,走的是soap协议。
    flex:一个在国外流行不起来,而在中国宣起一股热潮的技术,flex主要用于一些门户网站的应用,因为整个前台都是依赖flash组装而成,其华丽的效果是其他技术所无法比拟的,但是性能很差,就国外市场而言,前景不是很好。
    ext:和flex一样,主要也是做为界面美化而应用到的一门技术,与flex不同的是它更为适用,开发出来的产品性能更优越一些,所以在一些企业级开发里面较为使用。
    WebService:迄今为止最为热门话题之一,webService在跨平台使用方面显现出其突出的优势,它主要是依据XML做为传输媒介,促使各种应用平台进行效率较高的优化,一般较小的数据通信会用到它,而大数据量传输则需要用到soket一些技术。webService主要使用范围是远程(remote)跨平台的信息交互,而本地局域则没有以往的com组件等实现方式效率高。
    报表技术:报表技术主要分为一般报表和图形化报表,一般的如导入导出excel,word等都属于一般报表,而例如饼图,柱状图,曲线图等都属于图形化报表。其中一般报表主要是应用于书面存根,打印文书等,较为简单,而图形化报表,主要是其业务逻辑比较复杂,也可以说形成的sql语句会很复杂,所以无论在美观性能等方面都应该重视,现在图形化报表实现方式很多,我们的学员可以选择一两种进行理解即可,与此同时还需要了解一些图形化报表制作工具,例如ireport等。
    oracle深入和优化:用到oracle或者db2等一些大型数据库的系统的规模都将比较大,客户量较多,所以要求其开发人员不仅仅需要熟悉oracle的一些常见处理语句,比如查询重复字段,截取数据,授权,创建,导入导出,初始化空间大小,步长等常见的问题之外,更加需要懂一些性能优化,处理数据并发,死琐,数据库集群等问题。
    tomcate、weblogic、jboos服务器:这些都是常见的服务器,但是在真实应用当中,单个应用还是不够的,例如服务器集群、缓存处理、优化处理等。
    jboos集群:这个问题一般初级程序员可能不会问到,但是如果是工资要求在5K以上(深圳)就有可能会问到,集群问题很多,这里拿jboos为例来说明问题。jboos集群主要有session的复制,缓存处理,机群地址设置等,有兴趣的,可以去看看这方面的资料。
    单点技术:SSO,在现有的一些大型网站和综合系统开发中应用及为广泛,主要是适用于单个用户一次登陆的情况下,去操作所属权限的其他各应用系统。这是表现自身的一亮点,这里建议学员们多去看一下相关资料或者与老师讨教。
    ibitis:与hibernate一样,做数据持久层的轻量级应用,这个不需要深入去了解,提到它,主要是避免在考官问及时学员们只会说:不知道。利用其可以勾起考官对hibernate的兴趣。
    权限控制:几乎所有的应用系统上面都会涉及到这一个问题,虽然我们的学员学过一些相关的知识,但是很少人对其有深刻的认识,这是一个致命的弱点。权限控制不光需要我们知道它的原理以及作用,更要细化到表,甚至字段,近而联系数据库和应用平台去说明这一问题。
    线程:对于我们的学员而言,恐仅仅知道线程的实现种类,继承thread和实现runable接口,这些是完全不够的,如今企业中未必会在工程项目当中应用到线程,但很多都会问一些线程的相关内容,因为多线程的问题涉及到了项目的优化,BUG排除,技术应用等问题。我们企业级应用里面很多都讲究一个线程安全的问题,所谓的Synconized,即单线程,而IE支持的是多线程,Ajax默认也是多线程。有时候在多线程里面也可以通过手动控制的手段达到一个局部线程安全,这也优化程序一个常见的方案。在这里可以建议学员们去针对性的去找几个多线程题看看,再者了解几种线程安全的技术和非现成安全的技术。
    这些技术看着多,学起来根本不需要花费多少时间,所以深圳就业部考量实际情况,将这些纳入就业前技术强化的一部分。
    展开全文
  • 导读:对于工程经验比较丰富的同学,并发应该也并不是陌生的概念了,但是每个人所理解的并发问题,却又往往并不统一,本文系统梳理了百度C++工程师在进行并发优化时所作的工作。全文15706字,预计阅读时间24分钟。一...

    图片

    导读:对于工程经验比较丰富的同学,并发应该也并不是陌生的概念了,但是每个人所理解的并发问题,却又往往并不统一,本文系统梳理了百度C++工程师在进行并发优化时所作的工作。

    全文15706字,预计阅读时间24分钟。

    一、背景

    简单回顾一下,一个程序的性能构成要件大概有三个,即算法复杂度、IO开销和并发能力。由于现代计算机体系结构复杂化,造成很多时候,工程师的性能优化会更集中在算法复杂度之外的另外两个方向上,即IO和并发,在之前的《百度C++工程师的那些极限优化(内存篇)》中,我们介绍了百度C++工程师工程师为了优化性能,从内存IO角度出发所做的一些优化案例。

    图片

    这次我们就再来聊一聊另外一个性能优化的方向,也就是所谓的并发优化。和IO方向类似,对于工程经验比较丰富的同学,并发应该也并不是陌生的概念了,但是每个人所理解的并发问题,却又往往并不统一。所以下面我们先回到一个更根本的问题,重新梳理一下所谓的并发优化。

    二、为什么我们需要并发?

    是的,这个问题可能有些跳跃,但是在自然地进展到如何处理各种并发问题之前,我们确实需要先停下来,回想一下为什么我们需要并发?

    这时第一个会冒出来的概念可能会是大规模,例如我们要设计大规模互联网应用,大规模机器学习系统。可是我们仔细思考一下,无论使用了那种程度的并发设计,这样的规模化系统背后,都需要成百上千的实例来支撑。也就是,如果一个设计(尤其是无状态计算服务设计)已经可以支持某种小规模业务。那么当规模扩大时,很可能手段并不是提升某个业务单元的处理能力,而是增加更多业务单元,并解决可能遇到的分布式问题。

    其实真正让并发编程变得有价值的背景,更多是业务单元本身的处理能力无法满足需求,例如一次请求处理时间过久,业务精细化导致复杂度积累提升等等问题。那么又是什么导致了近些年来,业务单元处理能力问题不足的问题呈现更加突出的趋势?

    可能下面这个统计会很说明问题:

    (https://www.karlrupp.net/2015/06/40-years-of-microprocessor-trend-data/)

    图片

    上图从一个长线角度,统计了CPU的核心指标参数趋势。从其中的晶体管数目趋势可以看出,虽然可能逐渐艰难,但是摩尔定律依然尚能维持。然而近十多年,出于控制功耗等因素的考虑,CPU的主频增长基本已经停滞,持续增加的晶体管转而用来构建了更多的核心。

    从CPU厂商角度来看,单片处理器所能提供的性能还是保持了持续提升的,但是单线程的性能增长已经显著放缓。从工程师角度来看,最大的变化是硬件红利不再能透明地转化成程序的性能提升了。随时代进步,更精准的算法,更复杂的计算需求,都在对的计算性能提出持续提升的要求。早些年,这些算力的增长需求大部分还可以通过处理器更新换代来自然解决,可是随着主频增长停滞,如果无法利用多核心来加速,程序的处理性能就会随主频一同面临增长停滞的问题。因此近些年来,是否能够充分利用多核心计算,也越来越成为高性能程序的一个标签,也只有具备了充分的多核心利用能力,才能随新型硬件演进,继续表现出指数级的性能提升。而伴随多核心多线程程序设计的普及,如何处理好程序的并发也逐渐成了工程师的一项必要技能。

    图片

    上图描述了并发加速的基本原理,首先是对原始算法的单一执行块拆分成多个能够同时运行的子任务,并设计好子任务间的协同。之后利用底层的并行执行部件能力,将多个子任务在时间上真正重叠起来,达到真正提升处理速度的目的。

    需要注意的是还有一条从下而上的反向剪头,主要表达了,为了正确高效地利用并行执行部件,往往会反向指导上层的并发设计,例如正确地数据对齐,合理的临界区实现等。虽然加速看似完全是由底层并行执行部件的能力所带来的,程序设计上只需要做到子任务拆分即可。但是现阶段,执行部件对上层还无法达到透明的程度,导致这条反向依赖对于最终的正确性和性能依然至关重要。既了解算法,又理解底层设计,并结合起来实现合理的并发改造,也就成为了工程师的一项重要技能。

    三、单线程中的并行执行

    提到并行执行部件,大家的第一个印象往往时多核心多线程技术。不过在进入到多线程之前,我们先来看看,即使是单线程的程序设计中,依然需要关注的那些并行执行能力。回过头再仔细看前文的处理器趋势图其实可以发现,虽然近年主频不再增长,甚至稳中有降,但是单线程处理性能其实还是有细微的提升的。这其实意味着,在单位时钟周期上,单核心的计算能力依然在提升,而这种提升,很大程度上就得益于单核心单线程内的细粒度并行执行能力。

    3.1 SIMD

    其中一个重要的细粒度并行能力就是SIMD(Single Instruction Multiple Data),也就是多个执行单元,同时对多个数据应用相同指令进行计算的模式。在经典分类上,一般单核心CPU被归入SISD(Single Instruction Single Data),而多核心CPU被归入MIMD(Mingle Instruction Multiple D ata),而GPU才被归入SIMD的范畴。但是现代CPU上,除了多核心的MIMD基础模型,也同时附带了细粒度SIMD计算能力。

    图片

    图片

    上图是Intel关于SIMD指令的一个示意图,通过增加更大位宽的寄存器实现在一个寄存器中,“压缩”保存多个较小位宽数据的能力。再通过增加特殊的运算指令,对寄存器中的每个小位宽的数据元素,批量完成某种相同的计算操作,例如图示中最典型的对位相加运算。以这个对位相加操作为例,CPU只需要增大寄存器,内存传输和计算部件位宽,针对这个特殊的应用场景,就提升到了8倍的计算性能。相比将核心数通用地提升到8倍大小,这种方式付出的成本是非常少的,指令流水线系统,缓存系统都做到了复用。

    从CPU发展的视角来看,为了能够在单位周期内处理更多数据,增加核心数的MIMD强化是最直观的实现路径。但是增加一套核心,就意味增加一套 完整的指令部件、流水线部件和缓存部件,而且实际应用时,还要考虑额外的核心间数据分散和聚合的传输和同步开销。一方面高昂的部件需求, 导致完整的核心扩展成本过高,另一方面,多核心间传输和同步的开销针对小数据集场景额外消耗过大,还会进一步限制应用范围。为了最大限度利用好有限的晶体管,现代CPU在塑造更多核心的同时,也在另一个维度上扩展单核心的处理和计算位宽,从而实现提升理论计算性能(核心数 * 数据宽度)的目的。

    不过提起CPU上的SIMD指令支持,有一个绕不开的话题就是和GPU的对比。CPU上早期SIMD指令集(MMX)的诞生背景,和GPU的功能定位就十分类似,专注于加速图像相关算法,近些年又随着神经网络计算的兴起,转向通用矩阵类计算加速。但是由于GPU在设计基础上就以面向密集可重复计算负载设计,指令部件、流水线部件和缓存部件等可以远比CPU简洁,也因此更容易在量级上进行扩展。这就导致,当计算密度足够大,数据的传输和同步开销被足够冲淡的情况下(这也是典型神经网络计算的的特性),CPU仅作为控制流进行指挥,而数据批量传输到GPU协同执行反而 会更简单高效。

    由于Intel自身对SIMD指令集的宣传,也集中围绕神经网络类计算来展开,而在当前工程实践经验上,主流的密集计算又以GPU实现为主。这就导致了不少CPU上SIMD指令集无用论应运而生,尤其是近两年Intel在AVX512初代型号上的降频事件,进一步强化了『CPU就应该做好CPU该做的事情』这一论调。但是单单从这一的视角来认识CPU上的SIMD指令又未免有些片面,容易忽视掉一些真正有意义的CPU上SIMD应用场景。

    图片

    对于一段程序来讲,如果将每读取单位数据,对应的纯计算复杂度大小定义为计算密度,而将算法在不同数据单元上执行的计算流的相同程度定义为模式重复度,那么可以以此将程序划分为4个象限。在大密度可重复的计算负载(典型的重型神经网络计算),和显著小密度和非重复计算负载(例如HTML树状解析)场景下,业界在CPU和GPU的选取上其实是有相对明确“最优解”的。不过对于过渡地带,计算的重复特征没有那么强,  或者运算密度没有那么大的场景下,双方的弱点都会被进一步放大。即便是规整可重复的计算负载,随着计算本身强度减小,传输和启动成本逐渐显著。另一方面,即便是不太规整可重复的计算负载,随着计算负荷加大,核心数不足也会逐渐成为瓶颈。这时候,引入SIMD的CPU和引入SIMT 的GPU间如何选择和使用,就形成了没有那么明确,见仁见智的权衡空间。

    即使排除了重型神经网络,从程序的一般特性而言,具有一定规模的重复特性也是一种普遍现象。例如从概念上讲,程序中的循环段落,都或多或少意味着批量/重复的计算负载。尽管因为掺杂着分支控制,导致重复得没有那么纯粹,但这种一定规模的细粒度重复,正是CPU上SIMD发挥独特价值的地方。例如最常见的SIMD优化其实就是memcpy,现代的memcpy实现会探测CPU所能支持的SIMD指令位宽,并尽力使用来加速内存传输。另一方面现代编译器也会利用SIMD指令来是优化对象拷贝,进行简单循环向量化等方式来进行加速。类似这样的一类优化方法偏『自动透明』,也是默默支撑着主频不变情况下,性能稍有上升的重要推手。

    可惜这类简单的自动优化能做到的事情还相当有限,为了能够充分利用CPU上的SIMD加速,现阶段还非常依赖程序层进行主动算法适应性改造,有 目的地使用,换言之,就是主动实施这种单线程内的并发改造。一个无法自动优化的例子就是《内存篇》中提到的字符串切分的优化,现阶段通过编译器分析还很难从循环 + 判断分支提取出数据并行pattern并转换成SIMD化的match&mask动作。而更为显著的是近年来一批针对SIMD指令重新设计的算法,例如Swiss Table哈希表,simdjson解析库,base64编解码库等,在各自的领域都带来了倍数级的提升,而这一类算法适应性改造,就已经完全脱离了自动透明所能触及的范围。可以预知近些年,尤其随着先进工艺下AVX512降频问题的逐渐解决,还会/也需要涌现出更多的传统基础算法的SIMD改造。而熟练运用SIMD指令优化技术,也将成为C++工程师的一项必要技能。

    3.2 OoOE

    另一个重要的单线程内并行能力就是乱序执行OoOE(Out of Order Execution)。经典教科书上的CPU流水线机制一般描述如下(经典5级RISC流水线)。

    图片

    指令简化表达为取指/译码/计算/访存/写回环节,当执行环节遇到数据依赖,以及缓存未命中等场景,就会导致整体停顿的产生。其中MEM环节的影响尤其显著,主要也是因为缓存层次的深化和多核心的共享现象,带来单次访存所需周期数参差不齐的现象越来越严重。上图中的流水线在多层缓存下的表现,可能更像下图所示:

    图片

    为了减轻停顿的影响,现代面向性能优化的CPU一般引入了乱序执行结合超标量的技术。也就是一方面,对于重点执行部件,比如计算部件,访存部件等,增加多份来支持并行。另一方面,在执行部件前引入缓冲池/队列机制,通用更长的预测执行来尽可能打满每个部件。最终从流水线模式,转向了更类似『多线程』的设计模式:

    图片

    乱序执行系统中,一般会将通过预测维护一个较长的指令序列,并构建一个指令池,通过解析指令池内的依赖关系,形成一张DAG(有向无环图) 组织的网状结构。通过对DAG关系的计算,其中依赖就绪的指令,就可以进入执行态,被提交到实际的执行部件中处理。执行部件类似多线程模型中的工作线程,根据特性细分为计算和访存两类。计算类一般有相对固定可预期的执行周期,而访存类由于指令周期差异较大,采用了异步回调的模型,通过Load/Store Buffer支持同时发起数十个访存操作。

    乱序执行系统和传统流水线模式的区别主要体现在,当一条访存指令因为Cache Miss而无法立即完成时,其后无依赖关系的指令可以插队执行(类似于多线程模型中某个线程阻塞后,OS将其挂起并调度其他线程)。插队的计算类指令可以填补空窗充分利用计算能力,而插队的访存指令通过更早启动传输,让访存停顿期尽量重叠来减小整体的停顿。因此乱序执行系统的效率,很大程度上会受到窗口内指令DAG的『扁平』程度的影响,依赖深度较浅的DAG可以提供更高的指令级并发能力,进而提供更高的执行部件利用率,以及更少的停顿周期。另一方面,由于Load/Store Buffer也有最大的容量限制,处理较大区域的内存访问负载时,将可能带来更深层穿透的访存指令尽量靠近排布,来提高访存停顿的重叠,也能够有效减少整体的停顿。

    虽然理论比较清晰,可是在实践中,仅仅从外部指标观测到的性能表现,往往难以定位乱序执行系统内部的热点。最直白的CPU利用率其实只能表达线程未受阻塞,真实在使用CPU的时间周期,但是其实并不能体现CPU内部部件真正的利用效率如何。稍微进阶一些的IPC(Instruction Per Cyc le),可以相对深入地反应一些利用效能,但是影响IPC的因素又多种多样。是指令并行度不足?还是长周期ALU计算负载大?又或者是访存停顿过久?甚至可能是分支预测失败率过高?真实程序中,这几项问题往往是并存的,而且单一地统计往往又难以统一比较,例如10次访存停顿/20次ALU 未打满/30个周期的页表遍历,到底意味着瓶颈在哪里?这个问题单一的指标往往就难以回答了。

    3.3 TMAM

    TMAM(Top-down Microarchitecture Analysis Method)是一种利用CPU内部PMU(Performance Monitoring Unit)计数器来从上至下分解定位部件瓶颈的手段。例如在最顶层,首先以标定最大指令完成速率为标准(例如Skylake上为单周期4条微指令),如果无法达到标定,则认为瓶颈在于未能充分利用部件。进一步细分以指令池为分界线,如果指令池未满,但是取指部件又无法满负荷输出微指令,就表明『前端』存在瓶颈。另一种无法达到最大指令速率的因素,是『前端』虽然在发射指令到指令池,但是因为错误的预测,最终没有产出有效结果,这类损耗则被归入『错误预测』。除此以外的问题就是因为指令池调度执行能力不足产生的反压停顿,这一类被归为『后端』瓶颈。进一步例如『后端』瓶颈还可以根 据,停顿发生时,是否伴随了ALU利用不充分,是否伴随了Load/Store Buffer满负荷等因素,继续进行分解细化,形成了一套整体的分析方法。例如针对Intel,这一过程可以通过pmu-tools来被自动完成,对于指导精细化的程序瓶颈分析和优化往往有很大帮助。

    int array\[1024\];
    for (size\_t i = 0; i < 1024; i += 2) {
     int a = array\[i\];
     int b = array\[i + 1\];
     for (size\_t j = 0; j < 1024; ++j) { 
     a = a + b;
     b = a + b;}
     array\[i\] = a;
     array\[i + 1\] = b;
    }
    

    例如这是里演示一个多轮计算斐波那契数列的过程,因为计算特征中深层循环有强指令依赖,且内层循环长度远大于常规乱序执行的指令池深度, 存在较大的计算依赖瓶颈,从工具分析也可以印证这一点。

    图片图片

    程序的IPC只有1,内部瓶颈也显示集中在『后端』内部的部件利用效率(大多时间只利用了一个port),此时乱序执行并没有发挥作用。

    int array\[1024\];
    for (size\_t i = 0; i < 1024; i += 4) {
      int a = array\[i\];
      int b = array\[i + 1\];
      int c = array\[i + 2\];
      int d = array\[i + 3\];
      for (size\_t j = 0; j < 1024; ++j) {
        a = a + b;
        b = a + b;
        c = c + d;
        d = c + d;
      }
      array\[i\] = a;
      array\[i + 1\] = b;
      array\[i + 2\] = c;
      array\[i + 3\] = d;
    }
    

    这里演示了典型的的循环展开方法,通过在指令窗口内同时进行两路无依赖计算,提高了指令并行度,通过工具分析也可以确认到效果。

    图片图片

    不过实践中,能够在寄存器上反复迭代的运算并不常见,大多情况下比较轻的计算负载,搭配比较多的访存动作会更经常遇到,像下面的这个例子:

    struct Line {     
        char data\[64\];
    };
    Line\* lines\[1024\]; // 其中乱序存放多个缓存行
    for (size\_t i = 0; i < 1024; ++i) {   
      Line\* line = lines\[i\];
      for (size\_t j = 0; j < 64; ++j) {   
        line->data\[j\] += j; 
     }
    }
    

    这是一个非连续内存上进行累加计算的例子,随外层迭代会跳跃式缓存行访问,内层循环在连续缓存行上进行无依赖的计算和访存操作。

    图片

    可以看到,这一次的瓶颈到了穿透缓存后的内存访存延迟上,但同时内存访问的带宽并没有被充分利用。这是因为指令窗口内虽然并发度不低,不过因为缓存层次系统的特性,内层循环中的多个访存指令,其实最终都是等待同一行被从内存加载到缓存。导致真正触发的底层访存压力并不足以打满传输带宽,但是程序却表现出了较大的停顿。

    for (size\_t i = 0; i < 1024; i += 2) { 
      Line\* line1 = lines\[i\];
      Line\* line2 = lines\[i + 1\];
      ...
      for (size\_t j = 0; j < 64; ++j) { 
        line1->data\[j\] += j;
        line2->data\[j\] += j;
        ...
       }
     }
    

    图片

    通过调整循环结构,在每一轮内层循环中一次性计算多行数据,可以在尽量在停顿到来的指令窗口内,让更多行出于同时从内存系统进行传输。从统计指标上也可以看出,瓶颈重心开始从穿透访存的延迟,逐步转化向访存带宽,而实际的缓存传输部件Fill    Buffer也开始出现了满负荷运作的情况。

    3.4 总结一下单线程并发

    现代CPU在遇到主频瓶颈后,除了改为增加核心数,也在单核心内逐步强化并行能力。如果说多进程多线程技术的普及,让多核心的利用技术多少不那么罕见和困难,那么单核心内的并行加速技术,因为更加黑盒(多级缓存加乱序执行),规范性不足(SIMD),相对普及度和利用率都会更差一些。虽然硬件更多的细节向应用层暴露让程序的实现更加困难,不过困难和机会往往也是伴随出现的,既然客观发展上这种复杂性增加已经无可避免,那么是否能善加利用也成了工程师进行性能优化时的一项利器。随着体系结构的进一步复杂化,可见的未来一段时间里,能否利用一些体系结构的原理和工具来进行优化,也会不可避免地成为服务端工程师的一项重要技能。

    四、多线程并发中的临界区保护

    相比单线程中的并发设计,多线程并发应该是更为工程师所熟悉的概念。如今,将计算划分到多线程执行的应用技术本身已经相对成熟了,相信各个服务端工程师都有各自熟悉的队列+线程池的小工具箱。在不做其他额外考虑的情况下,单纯的大任务分段拆分,提交线程池并回收结果可能也仅仅是几行代码就可以解决的事情了。真正的难点,其实往往不在于『拆』,而在于『合』的部分,也就是任务拆分中无法避免掉的共享数据操作环节。如果说更高的分布式层面,还可以尽可能地利用Share Nothing思想,在计算发生之前,就先尽量通过任务划分来做到尽可能充分地隔离资源。但是深入到具体的计算节点内部,如果再进行一些细粒度的拆分加速时,共享往往就难以彻底避免了。如何正确高效地处理这些无法避免的共享问题,就涉及到并发编程中的一项重要技术,临界区保护。

    4.1 什么是临界区

    图片

    算法并发改造中,一般会产生两类段落,一类是多个线程间无需交互就可以独立执行的部分,这一部分随着核心增多,可以顺利地水平扩展。而另一类是需要通过操作共享的数据来完成执行,这部分操作为了能够正确执行,无法被多个核心同时执行,只能每个线程排队通过。因此临界区内的代码,也就无法随着核心增多来扩展,往往会成为多线程程序的瓶颈点。也是因为这个特性,临界区的效率就变得至关重要,而如何保证各个线程安全地通过临界区的方法,就是临界区保护技术。

    4.1.1 Mutual Exclusion

    图片

    最基本的临界区保护方法,就是互斥技术。这是一种典型的悲观锁算法,也就是假设临界区高概率存在竞争,因此需要先利用底层提供的机制进行仲裁,成功获得所有权之后,才进入临界区运行。这种互斥算法,有一个典型的全局阻塞问题,也就是上图中,当临界区内的线程发生阻塞,或被操作系统换出时,会出现一个全局执行空窗。这个执行空窗内,不仅自身无法继续操作,未获得锁的线程也只能一同等待,造成了阻塞放大的现象。但是对于并行区,单一线程的阻塞只会影响自身,同样位于在上图中的第二次阻塞就是如此。

    由于真实发生在临界区内的阻塞往往又是不可预期的,例如发生了缺页中断,或者为了申请一块内存而要先进行一次比较复杂的内存整理。这就会让阻塞扩散的问题更加严重,很可能改为让另一个线程先进入临界区,反而可以更快顺利完成,但是现在必须所有并发参与者,都一起等待临界区持有者来完成一些并没有那么『关键』的操作。因为存在全局阻塞的可能性,采用互斥技术进行临界区保护的算法有着最低的阻塞容忍能力,一般在『非阻塞算法』领域作为典型的反面教材存在。

    4.1.2 Lock Free

    图片

    针对互斥技术中的阻塞问题,一个改良型的临界区保护算法是无锁技术。虽然叫做无锁,不过主要是取自非阻塞算法等级中的一种分类术语,本质上是一种乐观锁算法。也就是首先假设临界区不存在竞争,因此直接开始临界区的执行,但是通过良好的设计,让这段预先的执行是无冲突可回滚的。但是最终设计一个需要同步的提交操作,一般基于原子变量CAS(Compare And Swap),或者版本校验等机制完成。在提交阶段如果发生冲突,那么被仲裁为失败的各方需要对临界区预执行进行回滚,并重新发起一轮尝试。

    无锁技术和互斥技术最大的区别是,临界区核心的执行段落是可以类似并行段落一样独立进行,不过又不同于真正的并行段落,同时执行的临界区中,只有一个是真正有效的,其余最终将被仲裁为无效并回滚。但是引入了冗余的执行操作后,当临界区内再次发生阻塞时,不会像互斥算法那样在参与线程之间进行传播,转而让一个次优的线程成功提交。虽然从每个并发算法参与线程的角度,存在没有执行『实质有效』计算的段落,但是这种浪费计算的段落,一定对应着另一个参与线程执行了『有效』的计算。所以从整个算法层面,能够保证不会全局停顿,总是有一些有效的计算在运行。

    4.1.3 Wait-Free

    图片

    无锁技术主要解决了临界区内的阻塞传播问题,但是本质上,多个线程依然是排队顺序经过临界区。形象来说,有些类似交通中的三叉路口汇合, 无论是互斥还是无锁,最终都是把两条车道汇聚成了一条单车道,区别只是指挥是否高明能保证没有断流出现。可是无论如何,临界区内全局吞吐降低成串行这点是共同的缺陷。

    而Wait Free级别和无锁的主要区别也就体现在这个吞吐的问题上,在无全局停顿的基础上,Wait Free进一步保障了任意算法参与线程,都应该在有限的步骤内完成。这就和无锁技术产生了区别,不只是整体算法时时刻刻存在有效计算,每个线程视角依然是需要持续进行有效计算。这就要求了多线程在临界区内不能被细粒度地串行起来,而必须是同时都能进行有效计算。回到上面三叉路口汇聚的例子,就以为着在Wait Free级别下,最终汇聚的道路依旧需要是多车道的,以保证可以同时都能够有进展。

    图片

    虽然理论角度存在不少有Wait Free级别的算法,不过大多为概念探索,并不具备工业使用价值。主要是由于Wait Free限制了同时有进展,但是并没有描述这个进展有多快。因此进一步又提出了细分子类,以比较有实际意义的Wait-Free Population Oblivious级别来说,额外限制了每个参与线程必须要在预先可给出的明确执行周期内完成,且这个周期不能和与参与线程数相关。这一点明确拒绝了一些类似线程间协作的方案(这些方案往往引起较大的缓存竞争),以及一些需要很长很长的有限步来完成的设计。

    图片

    上图实例了一个典型的Wait Free Population Oblivious思路。进行临界区操作前,通过一个协同操作为参与线程分配独立的ticket,之后每个参与线程可以通过获取到的ticket作为标识,操作一块独立的互不干扰的工作区,并在其中完成操作。工业可用的Wait Free算法一般较难设计,例如ticket机制要求在协调动作中原子完成工作区分配,而很多数据结构是不容易做到这样的拆分的。时至今日各种数据结构上工业可用的Wait    Free算法依旧是一项持续探索中的领域。

    4.2 无锁不是万能的

    从非阻塞编程的角度看,上面的几类临界区处理方案优劣有着显著的偏序关系,即Wait Free > Lock Free > Mutual Exclusion。这主要是从阻塞适应性角度进行的衡量,原理上并不能直接对应到性能纬度。但是依然很容易给工程师造成一个普适印象,也就是『锁是很邪恶的东西,不使用锁来实现算法可以显著提高性能』,再结合广为流传的锁操作自身开销很重的认知,很多工程师在实践中会有对锁敬而远之的倾向。那么,这个指导思想是否是完全正确的?

    让我们先来一组实验:

    // 在一个cache line上进行指定步长的斐波那契计算来模拟临界区计算负载
    uint64\_t calc(uint64\_t\* sequence, size\_t size) {
        size\_t i;
        for (i = 0; i < size; ++i) {
            sequence\[(i + 1) & 7\] += sequence\[i & 7\];
        }
        return sequence\[i & 7\];
    }
    {   // Mutual Exclusion
        ::std::lock\_guard<::std::mutex> lock(mutex);
        sum += calc(sequence, workload);
    }
    {   // Lock Free / Atomic CAS
        auto current = atomic\_sum.load(::std::memory\_order\_relaxed);
        auto next = current;
        do {
            next = current + calc(sequence, workload);
        } while (!atomic\_sum.compare\_exchange\_weak(
                     current, next, ::std::memory\_order\_relaxed));
    }
    {   // Wait Free / Atomic Modify
        atomic\_sum.fetch\_add(calc(sequence, workload), ::std::memory\_order\_relaxed);
    }
    

    这里采用多线程累加作为案例,分别采用上锁后累加,累加后CAS提交,以及累加后FAA(Fetch And Add)提交三种方法对全局累加结果做临界区保护。针对不同的并发数量,以及不同的临界区负载,可以形成如下的三维曲线图。

    其中Latency项除以临界区规模进行了归一,便于形象展示临界区负载变化下的临界区保护开销趋势,因此跨不同负载等级下不具备横向可比性。Cycles项表示多线程协同完成总量为同样次数的累加,用到的CPU周期总和,总体随临界区负载变化有少量天然倾斜。100/1600两个截面图将3中算法叠加在一起展示,便于直观对比。

    图片图片图片

    图片

    图片

    从上面的数据中可以分析出这样一些信息

    1、基于FAA的Wait Free模式各方面都显著胜过其他方法;

    2、无锁算法相比互斥算法在平均吞吐上有一定优势,但是并没有达到数量级水平;

    3、无锁算法随竞争提升(临界区大小增大,或者线程增多),cpu消耗显著上升;

    基于这些信息来分析,会发现一个和之前提到的『锁性能』的常规认知相悖的点。性能的分水岭并没有出现在基于锁的互斥算法和无锁算法中间, 而是出现在同为『未使用锁』的Lock Free和Wait Free算法中间。而且从CPU消耗角度来看,对临界区比较复杂,竞争强度高的场景,甚至Lock Free因为『无效预测执行』过多反而引起了过多的消耗。这表明了锁操作本身的开销虽然稍重于原子操作,但其实也并非洪水猛兽,而真正影响性能的,是临界区被迫串行执行所带来的并行能力折损。

    因此当我们遇到临界区保护的问题时,可以先思考一下,是否可以采用Wait Free的方法来完成保护动作,如果可以的话,在性能上能够接近完全消除了临界区的效果。而在多数情况下,往往还是要采用互斥或Lock Free来进行临界区的保护。此时临界区的串行不可避免,所以充分缩减临界区的占比是共性的第一要务,而是否进一步采用Lock Free技术来减少临界区保护开销,讨论的前提也是临界区已经显著很短,不会引起过多的无效预 测。除此以外,由于Lock Free算法一般对临界区需要设计成两阶段提交,以便支持回滚撤销,因此往往需要比对应的互斥保护算法更复杂,局部性也可能更差(例如某些场景必须引入链表来替换数组)。综合来看,一般如果无法做到Wait Free,那么无需对Lock Free过度执着,充分优化临界区的互斥方法往往也足以提供和Lock Free相当的性能表现了。

    4.3 并发计数器优化案例

    从上文针对临界区保护的多种方法所做的实验,还可以发现一个现象。随着临界区逐渐减小,保护措施开销随线程数量增加而提升的趋势都预发显著,即便是设计上效率和参与线程数本应无关的Wait Free级别也是一样。这对于临界区极小的并发计数器场景,依旧会是一个显著的问题。那么我们就先从锁和原子操作的实现角度,看看这些损耗是如何导致的。

    图片

    首先给出一个典型的锁实现,左侧是锁的fast path,也就是如果在外层的原子变量操作中未发现竞争,那么其实上锁和解锁其实就只经历了一组原子变量操作。当fast  path检测到可能出现冲突时,才会进入内核,尝试进行排队等待。fast  path的存在大幅优化了低冲突场景下的锁表现,而且现代操作系统内核为了优化锁的内存开销,都提供了『Wait On Address』的功能,也就是为了支持这套排队机制,每个锁常态只需要一个整数的存储开销即可,只有在尝试等待时,才会创建和占用额外的辅助结构。

    因此实际设计中,锁可以创建很多,甚至非常多,只要能够达到足够细粒度拆解冲突的效果。这其中最典型的就是brpc中计数器框架bvar的设计。

    图片

    这是bvar中基础统计框架的设计,局部计数和全局汇聚时都通过每个tls附加的锁来进行临界区保护。因为采集周期很长,冲突可以忽略不记,因此虽然默认使用了大量的锁(统计量 * 线程数),但是并没有很大的内存消耗,而且运行开销其实很低,能够用来支持任意的汇聚操作。这个例子也能进一步体现,锁本身的消耗其实并不显著,竞争带来的软件或硬件上的串行化才是开销的核心。

    图片

    不过即使竞争很低,锁也还是会由一组原子操作实现,而当我们自己查看原子操作时,实际是由cache锁操作保护的原子指令构成,而且这个指令会在乱序执行中起到内存屏障的效果降低访存重叠的可能性。因此针对非常常用的简单计数器,在百度内部我们进行了进一步去除局部锁的改造,来试图进一步降低统计开销。

    图片

    例如对于需要同时记录次数和总和的IntRecorder,因为需要两个64位加法,曾经只能依赖锁来保证原子更新。但随着新x86机型的不断普及,在比较新的X86和ARM服务端机型上已经可以做到128bit的原子load/store,因此可以利用相应的高位宽指令和正确对齐来实现锁的去除。

    图片

    另一个例子是Percentile分位值统计,由于抽样数据是一个多元素容器,而且分位值统计需要周期清空重算,因此常规也是采用了互斥保护的方法。不过如果引入版本号机制,将清空操作转交给计数线程自己完成,将sample区域的读写完全分离。在这个基础上,就可以比较简单的做到线程安全,而且也不用引入原子修改。严格意义上,异步清空存在边界样本收集丢失的可能性,不过因为核心的蓄水池抽样算发本身也具有随机性,在监控指标统计领域已经拥有足够精度。

    图片

    除了运行时操作,线程局部变量的组织方式原先采用锁保护的链表进行管理,采用分段数据结合线程编号的方法替换后,做到空间连续化。最终整体进一步改善了计数器的性能。

    image.png

    4.4 并发队列优化案例

    另一个在多线程编程中经常出现的数据结构就是队列,为了保证可以安全地处理并发的入队和出队操作,最基础的算法是整个队列用锁来保护起来。

    图片

    这个方法的缺点是显而易见的,因为队列往往作为多线程驱动的数据中枢位置,大量的竞争下,队列操作被串行很容易影响整体计算的并行度。因此一个自然的改进点是,将队列头尾分开保护,先将生产者和消费者解耦开,只追加必要的同步操作来保证不会过度入队和出队。这也是Jave中LinkedBlockingQueue所使用的做法。

    图片

    在头尾分离之后,进一步的优化进入了两个方向。首先是因为单节点的操作具备了Lock Free化的可能,因此产生了对应的Michael & Scott无锁队列算法。业界的典型实现有Java的ConcurrentLinkedQueue,以及boost中的boost::lockfree::queue。

    图片

    而另一个方向是队列分片,即将队列拆解成多个子队列,通过领取token的方式选择子队列,而子队列内部使用传统队列算法,例如tbb:: concurrent_queue就是分片队列的典型实现。

    图片

    image.png

    对两种方式进行对比,可以发现,在强竞争下,分片队列的效果其实显著胜过单纯的无锁处理,这也是前文对于无锁技术真实效果分析的一个体现。

    除了这类通用队列,还有一个强化竞争发布,串行消费的队列也就是bthread::ExecutionQueue,它在是brpc中主要用于解决多线程竞争fd写入的问题。利用一些有趣的技巧,对多线程生产侧做到了Wait Free级别。

    图片

    整个队列只持有队尾,而无队头。在生产侧,第一步直接将新节点和当前尾指针进行原子交换,之后再将之前的队尾衔接到新节点之后。因为无论是否存在竞争,入队操作都能通过固定的两步完成,因此入队算法是Wait Free的。不过这给消费侧带来的麻烦,消费同样从一个原子交换开始,将队尾置换成nullptr,之后的消费动作就是遍历取到的单链表。但是因为生产操作分了两部完成,此时可能发现部分节点尚处于『断链』状态,由于消费者无从知晓后续节点信息,只能轮询等待生产者最终完成第二步。所以理论上,生产/消费算法其实甚至不是Lock Free的,因为如果生产者在两阶段中间被换出,那么消费者会被这个阻塞传播影响,整个消费也只能先阻塞住。但是在排队写入fd的场景下,专项优化生产并发是合理,也因此可以获得更好的执行效率。

    image.png

    不过为了能利用原子操作完成算法,bthread::ExecutionQueue引入了链表作为数据组织方式,而链表天然存在访存跳跃的问题。那么是否可以用数组来同样实现Wait Free的生产甚至消费并发呢?

    这就是babylon::ConcurrentBoundedQueue所希望解决的问题了。

    不过介绍这个队列并发原理之前,先插入一个勘误信息。其实这个队列在《内存篇》最后也简单提到过,不过当时粗略的评测显示了acquire- release等级下,即使不做cache line隔离性能也可以保障。文章发表后收到业界同好反馈,讨论发现当时的测试用例命中了Intel Write Combining 优化技术,即当仅存在唯一一个处于等待加载的缓存行时,只写动作可以无阻塞提前完成,等缓存行真实加载完毕后,再统一提交生效。但是由于内存序问题,一旦触发了第二个待加载的缓存行后,对于第一个缓存行的Write Combine就无法继续生效,只能等待第二个缓存行的写完成后,才能继续提交。原理上,Write Combine技术确实缓解了只写场景下的False Sharing,但是只能等待一个缓存行的限制在真实场景下想要针对性利用起来限制相当大。例如在队列这个典型场景下,往往会同时两路操作数据和完成标记,很可能同时处于穿透加载中,此时是无法应用Write Combine技术的。此外,能够在缓存行加载周期内,有如此充分的同行写入,可能也只有并无真实意义的评测程序才能做到。所以从结论上讲,通常意义上的多线程cache line隔离还是很有必要的。

    图片

    回到babylon::ConcurrentBoundedQueue的设计思路上,其实是将子队列拆分做到极致,将同步量粒度降低到每个数据槽位上。每个入队和出队  请求,首先利用原子自增领取一个递增的序号,之后利用循环数组的存储方式,就可以映射到一个具体的数据槽位上。根据操作是入队还是出队, 在循环数组上发生了多少次折叠,就可以在一个数据槽位上形成一个连续的版本序列。例如1号入队和5号出队都对应了1号数据槽位,而1号入队预期的版本转移是0到1,而5号出队的版本转移是2到3。这样针对同一个槽位的入队和出队也可以形成一个连续的版本变更序列,一个领到序号的具体操作,只需要明确检测版本即可确认自己当前是否可以开始操作,并通过自己的版本变更和后续的操作进行同步。

    通过同步量下放到每个元素的方式,入队和出队操作在可以除了最开始的序号领取存在原子操作级别的同步,后续都可以无干扰并行开展。而更连续的数据组织,也解决了链表存储的访存跳跃问题。生产消费双端可并发的特点,也提供了更强的泛用性,实际在MPMC(Multiple Producer Mult iple Consumer)和MPSC(Multiple Producer Single Consumer)场景下都有不错的性能表现,在具备一定小批量处理的场景下尤其显著。

    图片

    招聘信息

    欢迎出色的C++ 工程师加入百度,与大神一起成长。关注同名公众号百度Geek说,输入内推即可,我们期待你的加入!

    推荐阅读

    百度C++工程师的那些极限优化(内存篇)

    |百度大规模Service Mesh落地实践

    一种基于实时分位数计算的系统及方法

    ---------- END ----------

    百度Geek说

    百度官方技术公众号上线啦!

    技术干货 · 行业资讯 · 线上沙龙 · 行业大会

    招聘信息 · 内推信息 · 技术书籍 · 百度周边

    欢迎各位同学关注

    展开全文
  • 其中测试驱动开发可以优化代码设计,提高代码的可测试性,建立和代码同步增长的自动化测试用例,根据迭代积累的经验和需求变化情况对计划进行不断的调整和细化。 ● 文化建设方面:实行激励机制,通过建立激励制度,...

    流程管理

    微服务从技术架构出发,使应用系统具备快速响应、灵活部署、敏捷交付、持续演进的特性成为可能,而规模化的微服务交付如果没有完整的软件工程和流程管理体系、自动化的流程交互运维工具,很难持续发展。

    敏捷方法论

    最早的软件开发是没有标准的,软件质量好坏完全取决于软件工程师的能力和素养。伴随着软件行业的发展,软件的整个开发流程需要 一 套 方 法 论 来 规 范 , CMMI ( Capability Maturity ModelIntegration,即能力成熟度模型集成)这种基于瀑布模式的标准软件开发流程解决了软件开发的标准化问题。在CMMI体系下,软件开发逐步向工程化迈进,但是也缺少了动态性和灵活性,人们开始反思传统方法的弊端,进而提出了敏捷方法。

    2001年2月,由Martin Fowler等17位软件开发专家起草的敏捷宣言发表,敏捷联盟成立。我们可以看到一个熟悉的名字:MartinFowler,微服务架构的概念最早也是他提出来的。

    下面我们了解一下敏捷宣言中敏捷软件开发的四个核心价值观。

    ● 个体和互动高于流程和工具:这里强调了人与人直接沟通的重要性和高效性,所以有了站立会议。但不要理解为完全不需要流程和工具,只是侧重人与人的沟通。

    ● 工作的软件高于详尽的文档:这里强调把更多的时间放在开发软件上。但并不是说文档就一点也不要写了,关键性的文档(项目整体流程描述及架构图等)还是要有的。

    ● 客户合作高于合同谈判:这里要区分公司属性,外包公司团队和企业自有项目团队肯定会采取不同的策略。这句话应该是讲给企业自有项目团队的,为了企业合作双方的利益,这个观点是正确的。但并不是说毫无底线地向客户妥协,而是提倡密切合作,以便提前发现问题,双方都可以减少损失,实现共赢。

    ● 响应变化高于遵循计划:这里道出了软件开发不可回避的问题,就是需求变更。站在企业整体利益的角度,需求变更是很正常的。随着市场变化、时间推移,之前的需求如果不做修改可能真的就影响了产品的落地效果。但这也不是说需求可以任意地变来变去,需要有既懂业务又懂技术的人来负责评估。

    Scrum(迭代式增量软件开发过程)是实现敏捷开发的具体方式之一,是一种具体实施方案和流程,也称为过程管理框架。Scrum的主要原则是缩短软件的交付周期,通过将过程分解为短期的工作循环,每一个循环为一个Sprint(冲刺),在每个Sprint中,由项目团队确定目标,Scrum团队由不同类型的人员组成,包括开发、测试、业务人员、美工等,每个团队的目标由项目管理者在计划会议上确定,团队可以自行确定实现Sprint目标的方法和途径,可以自行管理日常工作和计划的执行。

    微服务架构与敏捷研发流程一脉相承。微服务是将一个完整的系统分割成若干微小的、具备独立性的功能单元,每个功能单元是可以具备一个实际意义的小功能集。各个功能单元之间尽量是解耦或松耦合的,可以实现独立开发而不依赖其他功能单元。而敏捷保证微服务架构能够更好地适应需求的变化,保持团队的高效沟通,敏捷利用小型工作增量、频繁迭代与原型设计等手段,可以使我们摆脱大规模单体软件开发的风险。

    微服务架构更多地从技术的角度提升开发和运维的效率,而敏捷方法论贯穿了软件工程的整个流程,它重视流程、沟通、协作。可以说,敏捷在管理流程上是对微服务架构落地的有益补充和保障。

    DevOps转型

    随着软件开发敏捷化的推进,DevOps正在成为软件交付的最佳模式。DevOps是一种研发模式和一种方法论,从2009年开始逐渐流行起来。它不是框架或技术的东西,是更好的优化开发(DEV)、测试(QA)、运维(OPS)的流程,使开发运维一体化,通过高度自动化的工具与流程来使得软件构建、测试、发布更加快捷、频繁和可靠。

    DevOps的主要目的在于提高产品的交付能力与效率,要践行DevOps首先要改变的就是管理理念。

    DevOps其实包含了三个部分:开发、测试和运维。从单体架构转型到微服务架构后,我们可能面临开发、测试和运维诸多挑战,微服务架构需要借助DevOps方法论进行持续开发和持续集成的原因如下:

    ● 服务拆分成为细粒度的服务后,服务之间需要持续集成,才能完成整体的功能迭代,需要自动化测试、自动化交付。相比单体架构,微服务架构有更高频率的软件部署集成、发布、交付诉求。

    ● 大多数微服务架构使用容器和云平台,需要在流程上支持快速的发布流程,支持规模化的微服务交付场景。

    ● 要理解微服务之间的复杂交互,需要优秀的诊断与监控工具,

    而软件系统诊断与监控不仅仅是运维人员的职责,开发人员也需要深入参与到软件的交付和后期的系统运维和运营中,提升微服务之间交互的可观测性。

    软件团队DevOps转型需要从下面几个方面展开,这其中不仅包含技术的转型,也包含组织、流程等关键要素的转型。

    ● 技能方面:团队需要不断引入优秀的技术和好的设计来增强敏捷能力;保持良好的软件架构风格;集成工具链,搭建自动化软件集成、交付、发布平台。

    ● 组织与流程方面:DevOps需要组建一个自治的团队,使团队向全栈开发方向成长。另外需要融合不同的职能人员,比如开发人员和运维人员工作在同一个部门,向同一个领导汇报。

    要求开发人员和业务人员在整个项目开发期间必须天天在一起工作。需要建立激励体制和反省体制,团队每隔一定的时间在如何才能更有效地工作方面进行反省,然后对自己的行为进行调整。开发人员需要遵守相应的原则来保证进度。软件进度的唯一标准就是“能使用的软件”,优先要做的事是通过持续地交付有价值的软件来使客户满意。为了达到这个目的,在开发过程中要最小化可执行产品,持续集成/持续交付、持续部署(CI/CD),测试驱动开发(TDD)。交付的时间间隔越短越好,使用户经常看到软件效果。其中测试驱动开发可以优化代码设计,提高代码的可测试性,建立和代码同步增长的自动化测试用例,根据迭代积累的经验和需求变化情况对计划进行不断的调整和细化。

    ● 文化建设方面:实行激励机制,通过建立激励制度,强化和奖励那些引导组织朝着目标前进的行为。举行每日站立会议,进行高效的会议、记录问题并跟踪问题的解决过程;进行可视化管理,可视化管理可以让所有团队成员直观地获得当前项目的进度信息,及时暴露问题;保证团队理解一致并且适应变化,团队需要一定的敏捷理念,认清客户是逐步发现真正的需求的。总之,DevOps贯穿软件工程的整个生命周期,DevOps不只包含CI/CD方法论,除了技术和流程,它还包含企业管理文化。

    我们来深化学习微服务架构解析:微服务的采用前提,流程管理

    自动化管理工具

    在DevOps实践中,自动化管理工具的使用是非常重要的,下面让我们看看一些常用的代表性工具。

    ● IT基础设施自动化

    云服务:使用公有云(如阿里云、AWS等)服务,不需要买硬件服务器、租用机柜。私有云服务可以基于Kubernetes进行扩展构建。

    ● 代码管理

    Git:存储代码,管理代码的版本。

    ● 配置管理

    Chef:它是一个非常有用的DevOps工具,用于管理配置文件。使用此工具,DevOps团队可以避免跨10000台服务器进行配置文件的更改,相反,只需要在一个地方进行更改,然后自动反映在其他服务器上。

    ● 自动部署

    Jenkins:这个工具可以实行自动部署,有助于持续集成和测试。

    ● 交付镜像

    Docker:不仅可以交付软件代码,还能将代码依赖的工程运行环境一同打包进行交付。

    ● 日志管理

    ELK:这个工具可以收集、存储和分析所有日志。

    ● 性能管理

    App Dynamic:提供实时性能监控功能。此工具收集的数据有助于开发人员在出现问题时进行调试。

    ● 监控Nagios:当基础设施和相关服务宕机时,确保人们得到通知很重要,Nagios就是这样一个工具,它可以帮助DevOps团队发现和纠正问题。

    小结

    软件世界没有“银弹”,不存在理想的软件模型提供全面的解决方案。每一个公司或者企业都需要结合自身的情况和场景来选择是否采用微服务架构。如果你正在基于微服务架构构建或者改造你的系统,那么请注意你使用的技术理念和软件方法论与微服务架构是否存在冲突。总之,在软件工程中,除了技术因素,组织结构、研发流程等都会对微服务架构能否成功落地产生重要影响。

    展开全文
  • 8月1日,滨州市全市推进信息共享专项行动动员会议召开。据悉,经滨州市政府同意,市政府办公室印发了《滨州市深化“一次办好”改革推进信息共享专项行动实施方案》。方案要求,按照...
  • 会议明确了2019年药品上市后监管的重点任务,包括强化疫苗监管,强化疫苗批签发管理,加大对疫苗生产企业检查力度,挂牌督办疫苗违法案件;强化药品抽检和不良反应监测,强化网络售药监管,强化对高风险品种监管等。...
  • 以合同管理为突破口深化项目成本管理随着社会主义市场经济体制的逐步建立和完善,市场竞争愈来愈显激烈,企业作为一个经济组织,赢得利润、获取效益为其目的的本质表现更为突出。建设项目是施工企业效益的源泉,项目...
  • “互联网+政务服务”推进过程中存在着线上线下融合难、体制机制不完善、网上政务服务水平弱、发展环境亟待优化等问题,有必要从体制机制、基础支撑、人文关怀、法治环境等方面深入剖析这些痛点难点堵点的诱因,继而...
  • 强化了协作、敏捷、扩展性、可用性,以及通过优化的、更有效率的计算来降低成本的潜能。 更具体地说,云描述了由“资源池”化的计算、网络、信息和存储等组成的服务、应用、信息和基础设施等的使用。这些组件可以...
  • 工作改进基本可以分为三个阶段:一、简化,二、优化,三、固化。三个阶段着眼点不同,考核指标不一样,每个阶段都做好,工作改进才算完整有效。 一、 简化 该阶段旨在去繁就简、把握重点。都是重点,就是没有重点,...
  • 企业实施ERP系统,不是简单地通过计算机技术将企业现行业务流程固化,而是要按照建成现代化企业的目标将企业现行业务流程优化重组,并且让ERP系统支持优化重组了的业务流程,从而达到提高管理水平和运营效率的目的。...
  • 计算机视觉是否已经进入瓶颈期?

    千次阅读 2020-09-27 09:33:57
    作者:周博磊 ...来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 其实这个问题也是我近段时间一直在思考的问题....我的观点是:计算机视觉在人工智能和深度学习的大背景下方兴未艾....
  • 但在金融云环境下,传统网络技术架构受到了挑战:一方面虚拟化思想的出现,颠覆了原有的数据中心网络模型,使得传统网络技术已不足以适配云环境下产生的新场景,如虚拟机的出现要求网络颗粒度从物理机细化到了虚拟机...
  • 团队能够自我定义和优化产品和流程,自主持续改善。团队精神饱满,士气高涨,凝聚力好,战斗力强。团队成为组织的扎实基石。 真正的自组织团队需要组织的整体设计,具备三个特征: 从组织层面来说是 低耦合 。至少...
  • 我们的管理:IT管理

    万次阅读 2013-11-22 11:00:40
    制定好流程后,我们还校验我们的流程,发现多入口多出口、死循环、有分支无延展、有分支无出口、分支太多,这都是组织、岗位、层级、流程协作、流程效率有问题,我们会继续深化讨论流程。 我们的流程制定是严格遵守...
  •  本 规划立足《意见》对四类功能区域的划分,结合《全国主体功能区规划》确定的整体优化发展的定位,重点处理好优化与限制、优化与发展、优化与保护、优化与形 成差异化特色的关系,对全市功能区域进行优化深化和...
  • 深化公共部门特别是事业单位改革,动员民间和社会力量参与社会领域的改革和发展,加快推进影响长期发展的特殊领域政策调整,进一步推进公平的市场环境建设,加强对各个领域改革试点的宏观指导并优化考核机制。...
  • ERP

    千次阅读 2011-04-27 22:14:00
     Internet技术的成熟为企业信息管理系统增加与客户或供应商实现信息共享和直接的数据交换的能力,从而强化了企业间的联系,形成共同发展的生存链,体现企业为达到生存竞争的供应链管理思想。ERP系统相应实现这方面...
  •  研究目的:近年来,各地不断深化国有土地有偿使用制度改革,在培育有形市场、优化资源配置、促进公平竞争等方面发挥了积极作用。但由于财政体制、监管机制等方面的缺陷,也使土地有偿使用制度存在一定的局限性。...
  •  (1)改革开放特别是1998年以来,随着城镇住房制度改革的不断深化,北京 房地产业总体上保持了快速健康发展的势头,成为首都经济发展的重要支柱产业,政府住房保障力度逐步加大,已经初步形成了由廉租住房、经济适用...
  • 交通标志的检测与识别是一项十分艰巨的时代任务,要求相关工作人员认真在实践中进行思考和探索,保证对于交通标志进行细化的研究,这对于智能代步工具的发展起着非常重要的作用。关键词:交通标志;检测;识别;...
  • 24条举措,以黄金产融融合发展为主攻方向,从鼓励黄金金融业务创新、丰富黄金金融市场主体、进一步优化黄金金融发展生态环境、推进黄金金融开放合作等多个方面提出了一系列支持罗湖区黄金金融发展的细化政策措施。...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 242
精华内容 96
关键字:

强化优化深化细化