Ⅰ 什么是JIT
准时生产方式(Just In Time简称JIT),是日本丰田汽车公司在20世纪60年代实行的一种生产方式,1973年以后,这种方式对丰田公司渡过第一次能源危机起到了突出的作用,后引起其它国家生产企业的重视,并逐渐在欧洲和美国的日资企业及当地企业中推行开来,现在这一方式与源自日本的其它生产、流通方式一起被西方企业称为“日本化模式”,其中,日本生产、流通企业的物流模式对欧美的物流产生了重要影响,近年来,JIT不仅作为一种生产方式,也作为一种通用管理模式在物流、电子商务等领域得到推行。
在20世纪后半期,整个汽车市场进入了一个市场需求多样化的新阶段,而且对质量的要求也越来越高,随之给制造业提出的新课题即是,如何有效地组织多品种小批量生产,否则的话,生产过剩所引起的只是设备、人员、非必须费用等一系列的浪费,从而影响到企业的竞争能力以至生存。在这种历史背景下,1953年,日本丰田公司的副总裁大野耐一综合了单件生产和批量生产的特点和优点,创造了一种在多品种小批量混合生产条件下高质量、低消耗的生产方式即准时生产。准时制指的是,将必要的零件以必要的数量在必要的时间送到生产线,并且只将所需要的零件、只以所需要的数量、只在正好需要的时间送到生产。这是为适应20世纪60年代消费需要变得多样化、个性化而建立的一种生产体系及为此生产体系服务的物流体系。
[编辑本段]
【准时制核心思想】
在准时制生产方式倡导以前,世界汽车生产企业包括丰田公司均采取福特式的“总动员生产方式”,即一半时间人员和设备、流水线等待零件,另一半时间等零件一运到,全体人员总动员,紧急生产产品。这种方式造成了生产过程中的物流不合理现象,尤以库存积压和短缺为特征,生产线或者不开机,或者开机后就大量生产,这种模式导致了严重的资源浪费。丰田公司的准时制采取的是多品种少批量、短周期的生产方式,实现了消除库存,优化生产物流,减少浪费目的。
准时生产方式基本思想可概括为“在需要的时候,按需要的量生产所需的产品”,也就是通过生产的计划和控制及库存的管理,追求一种无库存,或库存达到最小的生产系统。准时生产方式的核心是追求一种无库存的生产系统,或使库存达到最小的生产系统。为此而开发了包括“看板””在内的一系列具体方法,并逐渐形成了一套独具特色的生产经营体系。
准时制生产方式以准时生产为出发点,首先暴露出生产过量和其他方面的浪费,然后对设备、人员等进行淘汰、调整,达到降低成本、简化计划和提高控制的目的。在生产现场控制技术方面,准时制的基本原则是在正确的时间,生产正确数量的零件或产品,即时生产。它将传统生产过程中前道工序向后道工序送货,改为后道工序根据“看板”向前道工序取货,看板系统是准时制生产现场控制技术的核心,但准时制不仅仅是看板管理。
[编辑本段]
【对生产制造的影响】
1.生产流程化
即按生产汽车所需的工序从最后一个工序开始往前推,确定前面一个工序的类别,并依次的恰当安排生产流程,根据流程与每个环节所需库存数量和时间先后来安排库存和组织物流。尽量减少物资在生产现场的停滞与搬运,让物资在生产流程上毫无阻碍地流动。
“在需要的时候,按需要的量生产所需的产品”。对于企业来说,各种产品的产量必须能够灵活地适应市场需要量的变比。众所周知,生产过剩会引起人员、设备、库存费用等一系列的浪费。避免这些浪费的手段就是实施适时适量生产,只在市场需要的时候生产市场需要的产品。
为了实现适时适量生产,首先需要致力于生产的同步化。即工序间不设置仓库,前一工序的加工结束后,使其立即转到下一工序去,装配线与机械加工几乎平行进行。在铸造、锻造、冲压等必须成批生产的工序,则通过尽量缩短作业更换时间来尽量缩小生产批量。生产的同步化通过“后工序领取”这样的方法来实现。 “后工序只在需要的时间到前工序领取所需的加工品;前工序中按照被领取的数量和品种进行生产。”这样,制造工序的最后一道即总装配线成为生产的出发点,生产计划只下达给总装配线,以装配为起点,在需要的时候,向前工序领取必要的加工品,而前工序提供该加工品后,为了补充生产被领走的量,必向再前道工序领取物料,这样把各个工序都连接起来,实现同步化生产。
这样的同步化生产还需通过采取相应的设备配置方法以及人员配置方法来实现。即不能采取通常的按照车、铣、刨等工业专业化的组织形式,而按照产品加工顺序来布置设备。这样也带来人员配置上的不同作法:弹性配置作业人数。降低劳动费用是降低成本的一个重要方面,达到这一目的的方法是“少人化”。所谓少人化,是指根据生产量的变动,弹性地增减各生产线的作业人数,以及尽量用较少的人力完成较多的生产。这里的关键在于能否将生产量减少了的生产线上的作业人员数减下来。具体方法是实施独特的设备布置,以便能够在需求减少时,将作业所减少的工时集中起来,以整顿削减人员。但这从作业人员的角度来看,意味着标准作业中的作业内容、范围、作业组合以及作业顺序等的一系列变更。因此为了适应这种变更,作业人员必须是具有多种技能的“多面手”。
2.生产均衡化
生产均衡化是实现适时适量生产的前提条件。所谓生产的均衡化,是指总装配线在向前工序领取零部件时应均衡地使用各种零部件,生产各种产品。为此在制定生产计划时就必须加以考虑,然后将其体现于产品生产顺序计划之中。在制造阶段,均衡化通过专用设备通用化和制定标准作业来实现。所谓专用设备通用化,是指通过在专用设备上增加一些工夹具的方法使之能够加工多种不同的产品。标准作业是指将作业节拍内一个作业人员所应担当的一系列作业内容标准化。
生产中将一周或一日的生产量按分秒时间进行平均,所有生产流程都按此来组织生产,这样流水线上每个作业环节上单位时间必须完成多少何种作业就有了标准定额,所在环节都按标准定额组织生产,因此要按此生产定额均衡地组织物质的供应、安排物品的流动。因为JIT生产方式的生产是按周或按日平均,所以与传统的大生产、按批量生产的方式不同,JIT的均衡化生产中无批次生产的概念。
标准化作业是实现均衡化生产和单件生产单件传送的又一重要前提。丰田公司的标准化作业主要是指每一位多技能作业员所操作的多种不同机床的作业程序,是指在标准周期时间内,把每一位多技能作业员所承担的一系列的多种作业标准化。丰田公司的标准化作业主要包括三个内容:标准周期时间、标准作业顺序、标准在制品存量,它们均用“标准作业组合表”来表示。
3.资源配置合理化
资源配置的合理化是实现降低成本目标的最终途径,具体指在生产线内外,所有的设备、人员和零部件都得到最合理的调配和分派,在最需要的时候以最及时的方式到位。
从设备而言,设备包括相关模具实现快速装换调整,例如,丰田公司发明并采用的设备快速装换调整的方法是SMED法。丰田公司所有大中型设备的装换调整操作均能够在10分钟之内完成,这为“多品种、小批量”的均衡化生产奠定了基础。
在生产区间,需要设备和原材料的合理放置。快速装换调整为满足后工序频繁领取零部件制品的生产要求和“多品种、小批量”的均衡化生产提供了重要的基础。但是,这种颇繁领取制品的方式必然增加运输作业量和运输成本,特别是如果运输不便,将会影响准时化生产的顺利进行。合理布置设备,特别是U型单元连结而成的“组合U型生产线”,可以大大简化运输作业,使得单位时间内零件制品运输次数增加,但运输费用并不增加或增加很少,为小批量频繁运输和单件生产单件传送提供了基础。
人员而言,多技能作业员(或称“多面手”)是指那些能够操作多种机床的生产作业工人。多技能作业员是与设备的单元式布置紧密联系的。在U型生产单元内,由于多种机床紧凑地组合在一起,这就要求并且便于生产作业工人能够进行多种机床的操作,同时负责多道工序的作业,如一个工人要会同时操作车床、铣床和磨床等。
[编辑本段]
【人力资源准时制方式的必要性】
实现人力资源的准时制至少可以给企业带来以下3个方面的好处:
1.减少人员维护成本。企业对内部员工不但要长期支付工资、福利等成本,而且要不断投入培训费用以提高和维持员工的各项技能。使用准时制人员,虽然可能一次性支出较大,但从长远观点看能节省很多成本。
2.不断吸收外部信息。通过准时制方式随时吸引外部人才的加入,能加强企业与外部的交流,及时取得各种有价值的信息,尤其是一些技术发展趋势方面的情况,往往从其他渠道难以得到。
3.集中力量于核心职能。实践证明,"大而全,小而全"的企业结构是效率低下的,目前出现的虚拟化管理的趋势,就是要把企业内部的部分职能逐渐分离出来,由社会或其他组织承担,从而使企业把非核心因素排除在企业组织之外,集中力量于企业的战略核心环节。我国进行的企业剥离部分社会职能、高校后勤社会化等一系列改革都体现了这种要求。
【人力资源准时制方式的可行性】
在计划经济体制下,人力资源管理的准时制方式是绝不可能实现的,但是随着市场经济的深入发展,准时制方式已成为可能,并且将发展成为一种常用的重要的方式。
1.随着人才市场的发展和完善,人员流动性增强,人才素质提高,从而对外部人才的可获性增强。烽火猎头认为众多的猎头公司、人才中心、咨询公司等都是可以利用的渠道,通过与这些公司的长期广泛联系,企业可以在需要的时候很容易地得到需要的人才,使准时制成为可能。尤其在我国,劳动力资源丰富的特点为企业采用准时制方式提供了资源保障。
2.用人制度的改革为JIT的实施提供方便。企业与个人之间新型的劳动合同关系消除了终身制的种种弊端,使得企业在用人方面拥有更大的主动性和灵活性。通过签订劳动合同,企业可以决定员工的聘用、待遇、绩效以及辞退等问题,也可以事先确定员工的服务时间,从而保证了准时制的顺利实施。
3.从国外经验看,准时制在人力资源管理中有着广泛的应用。在国外,早已出现的人才租赁公司为企业聘用准时制人员提供了帮助。据统计,美国约有20%的中小企业都采用人才租赁的方式,而人才租赁正是准时制一种主要方式。
[编辑本段]
【准时制人员的对象】
按照准时制的基本思想,企业中的任何人员都可能成为准时制管理的对象,只要企业出现人员需要,就要做到准时制。根据企业中各类人员的特点和作用,我们可以把准时制管理的对象分为两大类:
1.企业迫切需要的核心人员。一般来讲,企业的核心人员包括决策人员、管理人员、研究开发人员以及业务开发人员等等。这些核心人员决定了企业的综合竞争力,对于企业的生存和发展起着关键性的作用,他们是企业不可或缺的力量。因此,如果需要这部分人员,就必须及时补充,做到Just In Time.比如,由于业务扩展或人事变动,企业急需业务开发人员,人力资源管理部门就应当做到使所需人员及时到位,否则,将影响企业业务的开展。
有人认为,企业核心人员是企业的中坚力量,不应属于"随叫随到"的准时制人员。这是对准时制本质认识不清的结果,准时制要求在需要的时候提供需要的人员,并不涉及这种需要的时间长短。既然出现了对核心人员的需要,就应当使核心人员准时到位。尽管这类人员是企业长期需要的,而且也相对稳定,但其最初加入企业应当是Just In Time.
2.企业暂时需要的人员。这类人员虽然不构成企业的核心力量,但是他们的可获性将直接影响企业各项工作的顺利进行。这类人员可以是一些急需的专门人才,如产品开发人才、项目开发人才,因为这类人才只为特定产品或项目服务,企业没有必要长期拥有,因此可采用准时制方式临时雇佣,尤其对于一些中小企业,自身的技术力量不强,不能吸引或保留高层次技术人才,通过准时制方式获取外部人才将是一种理想的选择。另外,企业暂时需要的人员也可能是一些临时性或季节性工作要求的辅助人员,比如偶尔出现的货物运输、季节性的工作量增加,都需要使用准时制人员。由于这部分人员类型多、变动频繁,因此进行准时制开发的工作量相对较大,必须有科学详尽的准时制人员规划。
[编辑本段]
【准时制人员的规划】
准时制技术的一个重要特点就是严格的计划,为了适时地满足企业对人员的需要,同时又要消除人员的闲置,即不能靠大量"库存"来满足变动的需求,必须做好准时制人员的规划。一般应根据行业的商业周期或季节性规律,科学预计企业业务的发展变化对人员需求的影响,尤其是对临时需要人员的影响。
规划中,首先要确定准时制人员可能担任的工作清单,清单内容包括工作说明,工作所需的技能、知识,工作所需的方法、工具、设备,工作的质量要求,工作所需的培训时间及鉴定合格的标准等。然后根据工作清单,采取各种方式如提前招聘、租赁、兼职、顾问等,预先约定准时制人员,一旦需要就立即通知他们前来工作。如果是短期人力需求,工作结束后相应的准时制人员也结束临时聘用。
为保证准时制人员规划的顺利实施,应当建立详细的人才资源信息库,记录所有可以利用的外部人力资源,比如兼职人员、转换工作中的人士、精力充沛的退休人员、可以租赁的人才、自由职业者等等,并保持与这些人员的长期联系。人才库应当包括人员的特点、技能、爱好、联系方式、薪资要求等方面的信息,以便为企业预约准时制人员提供参考。
在人力资源开发与管理工作中,准时制既是一种技术,更是一种思想。它要求人力资源管理部门着眼于企业实际需要,周密计划、严格控制,既不能出现人员短缺,也不能有人员的闲置,这是一项非常困难而又很有意义的工作。
【准时制人员的供应商管理模式】
准时制对于供应商的管理需求为零库存计划,要求供应商生产物料严格按照订单生产,通过这种方式减少供应商的库存成本及浪费。从整个供应链上面体现出“零库存”的概念。
[编辑本段]
java领域的JIT
JIT Compiler(Just-in-time Compiler) 即时编译
最早的Java建置方案是由一套转译程式(interpreter),将每个Java指令都转译成对等的微处理器指令,并根据转译后的指令先后次序依序执行,由于一个Java指令可能被转译成十几或数十几个对等的微处理器指令,这种模式执行的速度相当缓慢。
针对这个问题,业界首先开发出JIT(just in time)编译器。当Java执行runtime环境时,每遇到一个新的类别(class:类别是Java程式中的功能群组),类别是Java程式中的功能群组-JIT编译器在此时就会针对这个类别进行编译(compile)作业。经过编译后的程式,被优化成相当精简的原生型指令码(native code),这种程式的执行速度相当快。花费少许的编译时间来节省稍后相当长的执行时间,JIT这种设计的确增加不少效率,但是它并未达到最顶尖的效能,因为某些极少执行到的Java指令在编译时所额外花费的时间可能比转译器在执行时的时间还长,针对这些指令而言,整体花费的时间并没有减少。
基于对JIT的经验,业界发展出动态编译器(dynamic compiler),动态编译器仅针对较常被执行的程式码进行编译,其余部分仍使用转译程式来执行。也就是说,动态编译器会研判是否要编译每个类别。动态编译器拥有两项利器:一是转译器,另一则是JIT,它透过智慧机制针对每个类别进行分析,然后决定使用这两种利器的哪一种来达到最佳化的效果。动态编译器针对程式的特性或者是让程式执行几个循环,再根据结果决定是否编译这段程式码。这个决定不见得绝对正确,但从统计数字来看,这个判断的机制正确的机会相当高。事实上,动态编译器会根据“历史资料”做决策,所以程式执行的时间愈长,判断正确的机率就愈高。以整个结果来看,动态编译器产生的程式码执行的速度超越以前的JIT技术,平均速度可提高至50%。
JIT 页面渲染引擎
JIT 页面渲染是 COMSHARP CMS 为了实现网站内容即时更新而开发的页面生成技术,JIT页面渲染引擎直接从数据库获取网站最新内容,瞬间生成页面输出给访问者,并通过 URL 转写技术实现纯静态地址。JIT 页面渲染技术是针对传统 CMS 生成静态 HTML 文件而言。传统 CMS 由于使用脚本代码模板技术,页面生成前,需要将数据库中的页面内容用外部模板进行解析与渲染,导致严重的性能问题,为了解决这个问题,传统 CMS 一般采用生成 HTML 静态文件技术,即,在内容创作完成后,对全站的内容执行一个静态 HTML 文件生成过程,最终,全站内容以静态 HTML 文件的形式存在。
静态 HTML 文件技术最显着的优势是性能出众,然而这种技术最严重的问题在于,用户对站点任何修改与更新,必须首先经过一次全站 HTML 文件重新生成过程,然后才能被访问者看到。根据不同 CMS 产品的性能和站点规模,这个 HTML 生成过程可能长到十几分钟到几十分钟或更长。也有个别 CMS 产品使用触发式页面渲染模式,即内容更新后,并不立即生成 HTML 文件,而是在用户第一次访问该页面时,触发生成该页面的 HTML 文件,这种技术的问题在于,用户第一次访问被更新页面的时候,可能经历非常漫长的等待,因为站点内各个页面之间并非孤立的,他们可能相互引用,虽然访问的只是一个页面,为了对引用页面同步更新,需要重新生成 HTML 文件的页面可能有多个。
JIT 页面渲染如何工作?
下图,是 COMSHARP CMS JIT 渲染引擎与传统 CMS 生成 HTML 静态页面模式对比。可以看出,JIT 渲染引擎直接将网站最新内容从数据库渲染给访问用户,而传统 CMS 的站点内容在到达访问用户之前,首先要经历一个 HTML 的转换过程。
COMSHARP CMS JIT 页面渲染如何实现毫秒级的渲染速度?
COMSHARP CMS 在页面渲染的时候,JIT 引擎可以在数十毫秒的时间内容完整整个页面的生成,这样就保证用户访问的时候,不会因 JIT 渲染造成延迟。事实上,COMSHARP CMS 网站访问速度只取决于服务器带宽,页面生成过程带来的延迟可以忽略不计。
我们有两项技术保证这样的性能:
编译级主题模板
COMSHARP CMS 的编译级主题模板直接内嵌在系统的 DLL 中,主题模板的套用是在运行时(Run Time)完成,这和传统 CMS 的调用脚本代码模板解释运行是截然不同。
调用 .NET 核心函数完成页面渲染(绕开 ASP.NET Webform 生命周期)
我们知道,.NET 框架内核性能是非常出色的,然而,ASP.NET Webform 却以效率低下而受到诟病。ASP.NET Webform 效率低下的主要原因,是微软为了在 Web 上实现类似 Winform 的开发体验而设计的一套机制,这套机制包含一个完整的 ASP.NET Webform 生命周期,Webform 从接受访问请求到输出页面内容,要经历一个周期,这个周期的存在是为了让开发者插入各种处理逻辑,这个 Webform 生命周期的效率并不理想。
为了解决这个问题,COMSHARP CMS 抛弃了 ASP.NET Webform 模式,而是直接调用 .NET 核心函数完成页面的输出,绕过 Webform 的生命周期,显着得提高了 COMSHARP CMS 页面的生成速度,并将速度提升到毫秒级。
Ⅱ jit的含义是什么
jit是just in time的缩写,常用的有两个领域,一个是工业中的准时生产系统,一个编程中即时编译编译器的缩写。
准时生产方法是指生产的产品能够精准地满足客户在时间、质量和数量上的需求,无论客户是产品的最终用户还是处于生产线上的其他流程。采用JIT时,配送到生产现场的部件和材料正如生产所需,企业不会为防止发生配送延迟的情况而储备材料和部件。
工业准时生产方法的核心
准时生产方法就是强调企业生产产品的时候,应该完全按照客户的需求来生产,客户什么时间需要,就什么时间生产出来,客户需要什么品种,就生产什么品种,客户需要多大量,就生产多大量,如果真正能做到这种程度,意味着企业生产出的产品马上就可以转移出去。
所以这种方法的核心就是按需生产,如果能实现按需生产,伴随着产品及时地转移,企业的存货库存就会不断降低,伴随着存货的不断降低,企业有关的成本也就会不断降低。
Ⅲ java中的JIT编译到底是什么意思
在JIT编译器生成本机代码后,它会重写存根例程,插入一个jmp指令跳转到刚才JIT编译器的代码。只有当要调用某个方法时,JIT编译器才会将CIL的方法体编译为相应的本机机器码版本。这样可以优化程序的工作集。
Ⅳ JIT(上):Tensorflow如何实现即时编译
Tensorflow的JIT(just-in-time)是指在运行 @tf.function 修饰的python函数时,由 jit 、 tf2xla 和 XLA 一起完成一系列如子图构造、子图优化、图编译和图执行等操作。编译后的可执行程序-- executable 会存放到cache中,供再次调用时直接获取执行。JIT的好处在 开篇 已经讲过了,这里不再赘述。
JIT的流程可以概括为:Tensorflow子图构造/优化,graph -> HLO,编译/执行,合并计算结果到Tensorflow图这四部分。本文只涉及图编译和图执行。
函数中ops在子图构造阶段被包裹进一个cluster node,并替换成 xla_compile 和 xla_run 这两op,而 XlaCompileOp 和 XlaRunOp 就是它们的 OpKernel ,分别用于图编译和执行。
XlaCompileOp通过 XlaCompilationCache 获取或编译executable,并将其封装成 XlaExecutableClosure ,并缓存在 XlaExecutableClosureStore 。 XlaRunOp 用从XlaCompileOp传递来的key在cache中查找并执行executable。
从编译流程图可以看到,XLA的编译结果会缓存到XlaCompilationCache,后续调用可以根据 signature 在cache中查找executable。
函数的 signature 是由 BuildSignature(function, args) 根据函数和arguments生成的。即使是同一个函数,只要input tensors不同,signature也会不一样,这就是 power() 被编译两次的原因:第三次函数调用时,由于无法通过signature在cache中找到executable而触发编译。
signature表示唯一的计算图:只要函数中的ops序列和arguments(type/shape)是确定的,那么计算图也是确定的。
编译之前需要通过 tf2xla 将图转换成XLA支持的语言 HLO 。tf2xla为每个Tensorflow op创建了生成HLO的 XlaOp ,因此,只要执行该Tensorflow子图,就可以生成具有相同的拓扑排序的HLO -- XlaComputation 。
XlaComputation (HLO)可以认为是一个运行在device上的纯函数,它的input/output会伴随着host-to-device(H2D)和device-to-host(D2H)的数据传输。
我们知道,Tensorflow图中的input tensor有两种: tf.Placeholder 和 tf.Variable ,前者每个step都会将新data发送到device,而后者是模型参数,它们会常驻内存,只在store/load checkpoint才会有H2D/D2H。
而纯函数的定义是:
不管是input还是output,虽然variable和其他argument一样存在于HLO的参数列表和返回值列表中,但它们实际上是常驻于device的,不需要也不应该H2D/D2H。
因此,HLO在编译时还需要通过 argument_input_indices 、 resource_input_indices 和 resource_update_to_input_index 等options来区分arguments和variables。
此外,如果有input是常数,为了避免无谓的H2D开销,可以把它固化到函数内部。同理,对于常数output,它没必要出现在函数中,可以直接定义在 XlaCompilationResult 的output buffer。
XlaCompilationResult是 Graph -> HLO 的output,它封装了HLO以及上述部分metadata、buffers。
XlaCompileOp会把编译好的executable、metadata、input/output buffers、options等统统封装进一个closure -- XlaExecutableClosure ,并将其缓存在 XlaExecutableClosureStore 供 XlaRunOp 获取。
XlaRunOp 可以通过一个数字字符串key(从0开始累加)从cache中查找并执行XlaExecutableClosure,这个key由XlaCompileOp提供。
Ⅳ matlab/simulink仿真中normal,Accelerator,Rapid Accelerator模式有什么区别求详细,谢谢
normal模式就是最传统的simulink引擎进行解算,逐个模块更新状态。
accelerator和Rapid Accelerator实际会用代码生成变为真正的可执行文件,省略了前期管理模型和动态翻译为机器语言的成本,会提高速度。而这两个应该是不同生成的等级。
也因为如此,normal模式只要正常安装了matlab即可正常仿真,而accelerator和rapid accelerator模式需要配置编译器支持,开始仿真前也需要有一个较长时间的编译过程。
希望可以帮助到你~
Ⅵ C#JIT的概念及作用
C#编写的程序,经过编译器把编译后,源代码被转换成Microsoft中间语言(MSIL)。MSIL不是真正可执行的代码。因此,要真正执行MSIL应用程序,还必须使用“JIT编译器”,对MSIL再次编译,以得到主机处理器可以真正执行本机指令。JIT编译器以即时方式编译MSMIL代码,以便应用程序执行。
Ⅶ 无法加载JIT编译器(CLR.DLL):文件可能丢失或损坏,请重新检查或重新安装,请问这个问题怎么解决!
您好
估计您的戴尔电脑系统有故障,您可以恢复出厂设置尝试
方法如下:(1)、开机进入系统前,按F8,进入Windows 7的高级启动选项,选择“修复计算机”。(2)、选择键盘输入方法。(3)、如果有管理员密码,需要输入;如果没有设置密码,直接“确定”即可。(4)、进入系统恢复选项后,选择“Dell DataSafe 还原和紧急备份”。(5)、选择“选择其他系统备份和更多选项”,点击“下一步”。(6)、选择“还原我的计算机”,点击“下一步”。(7)、选择正确的出厂映像后,点击“下一步”就可以开始恢复系统到出厂状态。注意,在恢复过程中,笔记本需要连接适配器。完成后,重启电脑即可。
Ⅷ 编程时选用的程序设计语言,对软件的开发与维护的影响
【CSDN 编者按】“如果我们把人类文明想象成汽车的话,那么软件开发行业就相当于汽车的引擎,编程语言就像引擎的燃料。”作为一名开发者,需跟随技术潮流的发展来学习新技术。2020年,你有计划新学一门编程语言吗?
本文作者从一名架构师的角度,详细分析了7种现代编程语言的优点与功能,你对哪门语言最感兴趣呢?
作者 | Md Kamaruzzaman,软件架构师
译者 | 弯月,责编 | 伍杏玲
封图| CSDN 下载于视觉中国
出品 | CSDN(ID:CSDNnews)
以下为译文:
如果我们把人类文明想象成汽车的话,那么软件开发行业就相当于汽车的引擎,而编程语言就像引擎的燃料。作为一名开发者,今年你应该学习哪种编程语言呢?
学习一种新的编程语言无疑是时间、精力和智力上的巨大投资, 但是学习一种新的编程语言可以提升你的软件开发技术力,促进你的职业发展。
在这里,我将献上一份现代编程语言的列表,这些语言不仅有助于提高你的生产力,而且还可以促进你的职业发展,并让你成长为更优秀的开发人员。这份列表还涵盖了非常广泛的领域:系统编程、应用程序开发、Web开发、科学计算等。
什么是现代编程语言?
“现代编程语言”这个说法本身就很含糊。许多人认为Python和JavaScript等语言是现代编程语言,还认为Java是一种古老的编程语言。实际上,这几种语言大约在同一时间出现:1995年。
大多数主流编程语言是上个世纪开发的:七十年代(如C)、八十年代(如C ++)、九十年代(如Java、Python、JavaScript)。这些语言在设计上并没有考虑现代软件开发生态系统:多核CPU、GPU、快速的互联网、移动设备、容器和云等。尽管许多语言中的许多功能都已进行一些改进,如并发等,而且在不断调整自己以适应时代,但它们依然保留了向后兼容性,无法抛弃那些过时的旧功能。
在这方面,Python就做得很好(某种意义上也未必是好事),Python 2和Python 3两者之间有明确的分界线。很多语言常常会为解决同一个问题提供十余种的方法,同时又没有顾及到开发人员的感受。根据StackOverflow的开发人员调查,大多数旧时的主流编程语言在“最可怕的语言”排名都名列前茅:
如果非要在新旧编程语言之间划个界限的话,那么应该是2007年6月29日,也就是第一台iPhone发行的时候。在这之后,编程语言界发生了很大变化。因此,在本文的列表中,我只考虑2007年以后的编程语言。
为什么要学习新语言?
首先,现代编程语言充分利用现代计算机硬件(多核CPU、GPU、TPU)、移动设备、大量数据、高速互联网、容器和云的优势。大多数现代编程语言会关注开发人员的体验,比如:
简洁明了的代码(减少样板代码)
内置的并发支持
空指针安全
类型推断
简洁的功能集
降低学习难度
融合所有编程范例的最佳功能
本文列表的许多编程语言都带有革命性地变化,并将永久地改变软件行业。一些已成为主流编程语言,还有一些则有望取得突破。因此选择这些语言作为第二种编程语言是明智的做法。
Rust
一直以来,系统编程语言环境主要由靠近硬件的语言(如C、C ++等)主导。尽管它们可以完全控制程序和硬件,但是它们缺乏内存安全性。即使它们支持并发,使用C/C ++编写并发程序也很困难,因为没有并发安全性。还有一些流行的编程语言是解释性语言,例如Java、Python、Haskell。这些语言具备安全性,但需要庞大的运行时或虚拟机。由于它们的运行时间长,因此Java等语言不适合于系统编程。
许多人曾尝试将C/C ++的功能与Java、Haskell的安全性相结合。然而,Rust才是第一个成功实现了这一点的编程语言。
Graydon Hoare在业余项目中开发出了Rust,他的灵感来自研究编程语言Cyclone。Rust是开源的,由Mozilla与许多其他公司和社区一起领导这门语言的开发。Rust于2015年首次发布,并很快引起了社区的关注。
主要特征:
通过所有权和借用概念提供内存安全和并发安全。
内存安全和并发安全在编译时确保,即如果程序代码可以编译,那么内存既安全又没有数据竞争。这是Rust最吸引人的功能。
它还提供了Haskell中元编程的表现力。凭借不可变的数据结构和功能编程功能,Rust提供了功能并发和数据并发。
Rust的速度非常快,纯Rust的性能甚至优于纯C。
在没有运行时的情况下,Rust可以完全控制现代硬件(TPU、GPU、多核CPU)。
Rust具有LLVM支持。因此,Rust提供一流的与WebAssembly的互操作性,而且Web代码也非常快。
流行度:
自2015年首次亮相以来,Rust已被开发人员广泛接受,并在StackOverflow开发人员调查中连续四年(2016、2017、2018、2019)被评选为最受欢迎的语言:
根据GitHub Octoverse的调查,Rust是运行速度第二快的语言,仅次于Dart:
此外,根据编程语言流行度排名网站PyPl的数据,Rust排名第18位,并呈上升趋势:
对比Rust提供的功能集,我们就会明白为什么微软、亚马逊、Google等科技巨头相继宣布投资Rust作为一种长期的系统编程语言。
根据Google统计的趋势,在过去的5年中,Rust的热度每年都在增加。
主要用途:
系统编程
Serverless 计算
商业应用
主要竞争对手:
C
C++
Go
Swift
Go
在本世纪初,Google面临两个扩展问题:开发扩展和应用程序扩展。开发扩展问题指的是他们不能仅通过投入开发人员的方式来添加更多功能。应用程序扩展问题则指他们无法开发出一款能够扩展到Google级别的计算机集群的应用程序。
所以在2007年左右,Google创建了一种新的编程语言,用于解决这两个扩展问题。两位才华横溢的Google软件工程师Rob Pike(UTF-8)和Ken Thompson(UNIX OS)创建了一种新语言。
2012年,Google正式发布了第一版的Go编程语言。Go是一种系统编程语言,但与Rust不同,它还具有Runtime和垃圾收集器(几兆字节)。但是与Java或Python不同,这个Runtime包含了生成的代码。最后,Go生成了一个本地的二进制代码,可以在没有附加依赖项或运行时的情况下在计算机中运行。
主要特征:
Go具有一流的并发支持。Go不通过线程和锁提供“共享内存”并发性,因为编程难度太大。相反,它提供了基于CSP的消息传递并发性(基于Tony Hoare的论文)。Go使用“ Goroutine”(轻量级绿色线程)和“ Channel”进行消息传递。
Go最大的杀手级功能是:简单,它是最简单的系统编程语言。新手软件开发人员只需几天就可以编写高效的代码,就像Python一样。有些大规模的云原生项目(如Kubernetes、Docker)都是用Go编写的。
Go还内置了垃圾收集器,这意味着开发人员无需担心C/C++中的内存管理问题。
Google投入了大量资金打造Go。因此Go拥有大量的工具支持。新手Go开发人员拥有大量的工具生态系统。
一般,开发人员80%的时间都花在了维护现有代码上,用于编写新代码的时间只占20%。由于其简单性,Go在语言维护方面表现出色。如今,Go在业务应用程序中大量使用。
流行度:
Go一问世就受到了软件开发社区热烈的欢迎。2009年-2018年,Go一直在TIOBE编程语言排行榜上徘徊。Go的成功为Rust等新一代编程语言铺平了道路。
如今,Go已是主流编程语言。最近,Go团队宣布了有关“Go 2”的消息,这门编程语言的发展会更加稳固。
几乎在所有的流行编程语言排行榜中,Go的排名都很高,已超过许多现有的语言。自2019年12月以来,在TIOBE指数排名中,Go名列第15位:
根据StackOverFlow的调查,十大最受喜爱的编程语言中,Go也位列其中:
此外,根据GitHub的数据,Go也是十大发展最迅速的语言之一:
Google趋势显示,在过去的5年中,Go的热度每年都在增加。
主要用途:
系统编程
Serverless 计算
商业应用
云原生开发
主要竞争对手:
C
C++
Rust
Python
Java
Kotlin
Java 是企业软件开发领域无可争议的王者。近年来,Java受到了一些负面评论:过于冗长,大量样板代码,容易出现意外的复杂性。但是,关于Java虚拟机(JVM)的争论却很少。JVM是软件工程的杰作,经过了时间的考验,提供了硬核的runtime。
多年来,Scala等JVM语言一直在努力克服Java的缺点,想成为更好的Java,但他们都失败了。最终,这场提升Java的探索以Kotlin的诞生结束。Jet Brains(流行的IDE IntelliJ背后的公司)开发了Kotlin,它可以在JVM上运行,克服了Java的很多缺点,提供许多现代功能。
与Scala不同的是,Kotlin比Java更简单,还可在JVM中提供与Go或Python开发人员同等的生产力。
Google宣布Kotlin是一流的Android应用开发语言,因此Kotlin在社区中的接受度得到了大幅提高。自2017年以来,同样受欢迎的Java Enterprise框架Spring也开始支持Kotlin。我曾尝试结合Kotlin与Reactive Spring使用,体验非常棒。
主要特征:
Kotlin的主要卖点在于其语言设计。我总是将Kotlin视为JVM上的Go/Python,因为它简洁明了的代码。因此,Kotlin的生产力很高。
与许多其他现代语言一样,Kotlin提供了Null指针、安全性、类型推断等功能。
由于Kotlin也运行在JVM中,因此现有Java库庞大的生态系统都可供使用。
Kotlin是一流的Android应用开发语言,并且已经超过Java,成为开发Android应用的首选。
Kotlin得到了JetBrains和Open Source的支持,因此具有出色的工具支持。
Kotlin有两个有趣的项目:Kotlin Native(将Kotlin编译为原生代码)和kotlin.js(Kotlin到JavaScript)。如果成功,则可以在JVM外部使用Kotlin。
Kotlin还提供了一种简单的方式来编写DSL(域特定语言)。
流行度:
自2015年首次发布以来,Kotlin的知名度不断飙升。根据Stack Overflow,Kotlin是2019年第四大最受欢迎的编程语言:
Kotlin还是增长最快的编程语言之一,排名第四:
在流行编程语言排名网站PyPl的排名中,Kotlin名列第十二名,并具有较高的上升趋势:
自从Google宣布Kotlin是一流的Android应用开发语言以来,Kotlin的流行趋势出现了大幅上涨,如下所示:
主要用途:
企业应用程序
主要竞争对手:
TypeScript
JavaScript是一门优秀的编程语言,在2015年之前,JavaScript有很多缺点。着名的软件工程师Douglas Crockford写了一本书名为《JavaScript: The Good Parts》,暗示了JavaScript有很糟的部分。无模块化,还有“回调地狱”,因此开发人员都不喜欢维护特别大的JavaScript项目。
Google甚至还开发了一个平台,可将Java代码反编译为JavaScript代码(GWT)。许多公司和个人都曾尝试开发更好的JavaScript,例如CoffeeScript、Flow、ClojureScript。最终,微软的TypeScript取得了成功。
微软的一队工程师在着名的Anders Hejlsberg的带领下,创建了JavaScript的静态类型、模块化超集——TypeScript。
TypeScript可以编译为JavaScript。于2014年首次发布后,TypeScript很快引起了社区的关注。Google当时还计划开发JavaScript的静态类型超集。Google对TypeScript青睐有加,以至于他们没有开发新的语言,而是选择与微软合作改进TypeScript。
Google选择TypeScript作为其SPA框架Angular 2+的主要编程语言。此外,流行的SPA框架React也提供对TypeScript的支持。另一个流行的JavaScript框架Vue.js也宣布将使用TypeScript开发新的Vue.js 3:
另外,node.js的创建者Ryan Dahl已决定使用TypeScript来开发安全的Node.js替代品Deno。
主要特征:
流行度:
开发人员喜欢TypeScript的优雅语言设计。在StackOverFlow最受欢迎的语言类别的调查中,TypeScript与Python并列第二名:
根据GitHub的排名,TypeScript是增长最快的编程语言之一,排名第五:
从GitHub的贡献度来看,TypeScript排名第七,打进了前十:
Google的趋势表明,在过去的几年中,TypeScript的热度越来越高:
主要用途:
主要竞争对手:
Swift
当初乔布斯拒绝在iOS中支持Java(和JVM),他认为Java不再是主流编程语言。如今我们发现乔布斯当初的估计是错的,虽然iOS仍然不支持Java。苹果选择了Objective-C作为iOS中的首选编程语言。Objective-C是一门很难掌握的语言,它不支持现代编程语言所要求的高生产力。
后来,苹果的Chris Lattner和其他人开发了一种多范例、通用的、编译编程语言——Swift,来替代Objective-C。Swift的第一个稳定版本于2014年发布。Swift还支持LLVM编译器工具链(也由Chris Lattner开发)。Swift与Objective-C代码库具有出色的互操作性,并且已确立为iOS应用开发中的主要编程语言。
主要特征:
流行度:
开发人员对Swift的喜爱不亚于许多其他现代编程语言。根据StackOverflow的调查,Swift在最受欢迎的编程语言中排名第六:
2019年,在TIOBE的编程语言排名中,Swift的排名上升到了第10名。鉴于这种编程语言只有5年的历史,可以说是成绩斐然:
Google的趋势表明,在过去的几年中,Swift的热度出现了激增:
主要用途:
主要竞争对手:
Dart
Dart是Google出品的第二大编程语言。Google是Web和Android领域的巨头,因此Google在Web和应用领域开发自己的编程语言也不足为奇。在丹麦软件工程师Lars Bak(领导Chrome的 JavaScript V8引擎开发)的带领下,Google于2013年发布了Dart。
Dart是一种通用编程语言,支持“强类型”和“面向对象”编程。Dart也可以转编译为JavaScript,凡是JavaScript可以运行的任何地方(例如Web、移动、服务器)几乎都可以运行 Dart。
主要特征:
流行度:
根据GitHub Octoverse数据显示,Dart是2019年增长最快的编程语言,去年它的流行度增长了五倍:
根据TIOBE指数显示,Dart排名第23,仅用了4年时间就超过了很多其他的现代编程语言:
根据StackOverflow的调查,Dart在最受欢迎的编程语言中排名第12:
受Flutter的影响,Google的趋势表明,在过去的两年中,Dart的热度急剧上升:
主要用途:
主要竞争对手:
Julia
本文提及的大多数编程语言都是由大型公司开发的,但Julia是个例外。科技计算领域通常都会使用动态语言,例如Python、Matlab。虽然这些语言提供易于使用的语法,但不适用于大规模的科技计算。他们需要使用C/C ++库执行CPU密集型任务,因此这就产生了着名的“两种语言”的问题,因为他们需要粘合代码来绑定两种语言。由于编写的代码需要在两种语言之间来回切换,因此总是会损失部分性能。
为了解决这个问题,麻省理工学院的一队研究人员计划从头开始创建一种新的语言,这种语言既可以利用现代硬件的优势,而且还结合其他语言的优势。于是,Julia诞生了。
Julia是一种动态的高级编程语言,提供一流的并发、并行和分布式计算支持。Julia的第一个稳定版本于2018年发布,并很快受到社区和行业的关注。Julia可用于科学计算、人工智能和许多其他领域,而且还可以解决“两种语言”的问题。
主要特征:
流行度:
Julia在许多领域主要与Python竞争。由于Python是最流行的编程语言之一,因此Julia想晋升主流还需要几年的时间。
虽然Julia非常新(只有一岁),但仍在TIOBE指数中排到第43名:
Google趋势显示,在过去的一年中,Julia的热度在稳步增长:
但是考虑到Julia的功能集,以及NSF、DARPA、NASA、因特尔等公司的推动,相信Julia取得突破的进展只是时间的问题。
主要用途:
主要竞争对手:
原文链接:https://towardsdatascience.com/top-7-modern-programming-language-to-learn-now-156863bd1eec
本文为 CSDN 翻译,转载请注明来源出处。
【End】
Python
Matlab
科学计算
高性能计算
数据科学
可视化
与Rust一样,Julia的主要特征在于语言的设计。这种语言在不牺牲性能的情况下,将高性能和科学计算中现有编程语言的一些功能结合在一起。就目前的情况来看,Julia出色地完成了这项任务。
Julia是一种动态编程语言,支持类型系统但类型不是必须的。因此,Julia这种编程语言很容易学习,生产力很高。
Julia的核心是多调度编程范例。
Julia内部支持并发、并行和分布式计算。
Julia为I/O密集型任务提供异步I/O。
Julia的运行速度非常快,可用于需要数百万个线程的科学计算。
JavaScript
TypeScript
应用开发
UI开发
与Go一样,Dart也非常注重开发人员的工作效率。由于Dart简洁的语法,以及高效的生产力,受到开发人员的喜爱。
Dart还提供“强类型”和“面向对象”编程。
Dart是少数同时支持JIT编译(运行时编译)和AOT编译(创建时编译)的编程语言之一。因此,Dart可以针对JavaScript运行时(V8引擎),并且Dart可以编译为快速的原生代码(AOT编译)。
跨平台原生应用程序开发平台Flutter选择了Dart作为开发iOS和Android应用的编程语言。从那以后,Dart的流行度越来越高。
与Goog的Go编程语言一样,Dart也具有出色的工具支持和庞大的Flutter生态系统。Flutter的日益普及也会推动Dart的采用率升高。
Objective-C
Rust
Go
iOS应用开发
系统编程
客户端开发(通过WebAssembly)
Swift的杀手级功能之一是其语言设计。语言本身很简单,语法简洁,比Objective-C更高效。
Swift还提供了现代程序语言的功能:null安全。此外,它还提供了语法糖来避免“厄运金字塔”。
作为一种编译语言,Swift和C++一样快。
Swift支持LLVM编译器工具链。因此,我们可以在服务器端编程,甚至浏览器编程(使用WebAssembly)中使用Swift。
Swift提供了自动引用计数(ARC)支持,可抑制内存管理的不善。
JavaScript
Dart
Web UI开发
服务器端开发
与Go或Kotlin同样,TypeScript的主要特征也是语言设计。TypeScript凭借其简洁明快的代码,成为了目前最优雅的编程语言之一。就开发人员的生产力而言,它与JVM或Go/Python上的Kotlin并驾齐驱。TypeScript是生产力最高的JavaScript超集。
TypeScript是JavaScript的强类型超集,特别适合大型项目,而且可以称为“可扩展的JavaScript”。
单页应用程序框架的“三巨头”(Angular、React、Vue.js)为TypeScript提供了出色的支持。在Angular中,TypeScript是首选的编程语言。在React和Vue.js中,TypeScript越来越受欢迎。
最大的两家技术巨头:微软和Google正在合作开发由活跃的开源社区支持的TypeScript。因此,TypeScript拥有最好的工具支持。
由于TypeScript是JavaScript的超集,因此凡是可以运行JavaScript的任何地方都可以运行TypeScript,包括浏览器、服务器、移动设备、物联网设备和云。
Java
Scala
Python
Go
Ⅸ 我现在想用matlab调用c#生成的dll
不是的,.net的dll是NET.addAssembly结构,是一般的PE结构的扩展,它需要.net框架中的JIT(实时编译),才能转化为机器码,所以不能用普通的方式加载。而Matlab似乎就是使用了loadlibrary一类的加载方式来加载 dll ,这样自然就不能了。
Ⅹ 了解什么叫做jit compiling,与传统的编译技术有何不同
Java 应用程序的性能经常成为开发社区中的讨论热点。因为该语言的设计初衷是使用解释的方式支持应用程序的可移植性目标,早期
Java 运行时所提供的性能级别远低于 C 和
C++
之类的编译语言。尽管这些语言可以提供更高的性能,但是生成的代码只能在有限的几种系统上执行。在过去的十年中,Java
运行时供应商开发了一些复杂的动态编译器,通常称作即时(Just-in-time,JIT)编译器。程序运行时,JIT
编译器选择将最频繁执行的方法编译成本地代码。运行时才进行本地代码编译而不是在程序运行前进行编译(用 C 或
C++ 编写的程序正好属于后一情形),保证了可移植性的需求。有些 JIT 编译器甚至不使用解释程序就能编译所有的代码,但是这些编译器仍然通过在程序执行时进行一些操作来保持 Java 应用程序的可移植性。
由于动态编译技术的多项改进,在很多应用程序中,现代的 JIT 编译器可以产生与 C 或 C++
静态编译相当的应用程序性能。但是,仍然有很多软件开发人员认为 —— 基于经验或者传闻 ——
动态编译可能严重干扰程序操作,因为编译器必须与应用程序共享 CPU。一些开发人员强烈呼吁对 Java
代码进行静态编译,并且坚信那样可以解决性能问题。对于某些应用程序和执行环境而言,这种观点是正确的,静态编译可以极大地提高 Java
性能,或者说它是惟一的实用选择。但是,静态地编译 Java 应用程序在获得高性能的同时也带来了很多复杂性。一般的
Java 开发人员可能并没有充分地感受到 JIT 动态编译器的优点。
本文考察了 Java 语言静态编译和动态编译所涉及的一些问题,重点介绍了实时 (RT) 系统。简要描述了 Java
语言解释程序的操作原理并说明了现代 JIT 编译器执行本地代码编译的优缺点。介绍了 IBM 在 WebSphere Real Time 中发布的
AOT 编译技术和它的一些优缺点。然后比较了这两种编译策略并指出了几种比较适合使用 AOT
编译的应用程序领域和执行环境。要点在于这两种编译技术并不互斥:即使在使用这两种技术最为有效的各种应用程序中,它们也分别存在一些影响应用程序的优缺
点。
执行 Java 程序
Java 程序最初是通过 Java SDK 的 javac程序编译成本地的与平台无关的格式(类文件)。可将此格式看作 Java
平台,因为它定义了执行 Java 程序所需的所有信息。Java 程序执行引擎,也称作 Java 运行时环境(JRE),包含了为特定的本地平台实现
Java 平台的虚拟机。例如,基于 Linux 的 Intel x86 平台、Sun Solaris 平台和 AIX 操作系统上运行的 IBM
System p 平台,每个平台都拥有一个 JRE。这些 JRE 实现实现了所有的本地支持,从而可以正确执行为
Java 平台编写的程序。
事实上,操作数堆栈的大小有实际限制,但是编程人员极少编写超出该限制的方法。JVM 提供了安全性检查,对那些创建出此类方法的编程人员进行通知。
Java 平台程序表示的一个重要部分是字节码序列,它描述了 Java
类中每个方法所执行的操作。字节码使用一个理论上无限大的操作数堆栈来描述计算。这个基于堆栈的程序表示提供了平台无关性,因为它不依赖任何特定本地平台
的 CPU 中可用寄存器的数目。可在操作数堆栈上执行的操作的定义都独立于所有本地处理器的指令集。Java
虚拟机(JVM)规范定义了这些字节码的执行(参见 参考资料)。执行 Java 程序时,用于任何特定本地平台的任何 JRE 都必须遵守 JVM
规范中列出的规则。
因为基于堆栈的本地平台很少(Intel X87 浮点数协处理器是一个明显的例外),所以大多数本地平台不能直接执行 Java 字节码。为了解决这个问题,早期的 JRE 通过解释字节码来执行 Java 程序。即 JVM 在一个循环中重复操作:
◆获取待执行的下一个字节码;
◆解码;
◆从操作数堆栈获取所需的操作数;
◆按照 JVM 规范执行操作;
◆将结果写回堆栈。
这种方法的优点是其简单性:JRE 开发人员只需编写代码来处理每种字节码即可。并且因为用于描述操作的字节码少于 255 个,所以实现的成本比较低。当然,缺点是性能:这是一个早期造成很多人对 Java 平台不满的问题,尽管拥有很多其他优点。
解决与 C 或 C++ 之类的语言之间的性能差距意味着,使用不会牺牲可移植性的方式开发用于 Java 平台的本地代码编译。
编译 Java 代码
尽管传闻中 Java 编程的 “一次编写,随处运行”
的口号可能并非在所有情况下都严格成立,但是对于大量的应用程序来说情况确实如此。另一方面,本地编译本质上是特定于平台的。那么 Java
平台如何在不牺牲平台无关性的情况下实现本地编译的性能?答案就是使用 JIT 编译器进行动态编译,这种方法已经使用了十年(参见图 1):
图 1. JIT 编译器
使用 JIT 编译器时,Java
程序按每次编译一个方法的形式进行编译,因为它们在本地处理器指令中执行以获得更高的性能。此过程将生成方法的一个内部表示,该表示与字节码不同但是其级
别要高于目标处理器的本地指令。(IBM JIT
编译器使用一个表达式树序列表示方法的操作。)编译器执行一系列优化以提高质量和效率,最后执行一个代码生成步骤将优化后的内部表示转换成目标处理器的本
地指令。生成的代码依赖运行时环境来执行一些活动,比如确保类型转换的合法性或者对不能在代码中直接执行的某些类型的对象进行分配。JIT
编译器操作的编译线程与应用程序线程是分开的,因此应用程序不需要等待编译的执行。
图 1 中还描述了用于观察执行程序行为的分析框架,通过周期性地对线程取样找出频繁执行的方法。该框架还为专门进行分析的方法提供了工具,用来存储程序的此次执行中可能不会改变的动态值。
因为这个 JIT 编译过程在程序执行时发生,所以能够保持平台无关性:发布的仍然是中立的 Java 平台代码。C 和 C++ 之类的语言缺乏这种优点,因为它们在程序执行前进行本地编译;发布给(本地平台)执行环境的是本地代码。
挑战
尽管通过 JIT 编译保持了平台无关性,但是付出了一定代价。因为在程序执行时进行编译,所以编译代码的时间将计入程序的执行时间。任何编写过大型 C 或 C++ 程序的人都知道,编译过程往往较慢。
为了克服这个缺点,现代的 JIT
编译器使用了下面两种方法的任意一种(某些情况下同时使用了这两种方法)。第一种方法是:编译所有的代码,但是不执行任何耗时多的分析和转换,因此可以快
速生成代码。由于生成代码的速度很快,因此尽管可以明显观察到编译带来的开销,但是这很容易就被反复执行本地代码所带来的性能改善所掩盖。第二种方法是:
将编译资源只分配给少量的频繁执行的方法(通常称作热方法)。低编译开销更容易被反复执行热代码带来的性能优势掩盖。很多应用程序只执行少量的热方法,因
此这种方法有效地实现了编译性能成本的最小化。
动态编译器的一个主要的复杂性在于权衡了解编译代码的预期获益使方法的执行对整个程序的性能起多大作用。一个极端的例子是,程序执行后,您非常清楚哪些方
法对于这个特定的执行的性能贡献最大,但是编译这些方法毫无用处,因为程序已经完成。而在另一个极端,程序执行前无法得知哪些方法重要,但是每种方法的潜
在受益都最大化了。大多数动态编译器的操作介于这两个极端之间,方法是权衡了解方法预期获益的重要程度。
Java 语言需要动态加载类这一事实对 Java
编译器的设计有着重要的影响。如果待编译代码引用的其他类还没有加载怎么办?比如一个方法需要读取某个尚未加载的类的静态字段值。Java
语言要求第一次执行类引用时加载这个类并将其解析到当前的 JVM
中。直到第一次执行时才解析引用,这意味着没有地址可供从中加载该静态字段。编译器如何处理这种可能性?编译器生成一些代码,用于在没有加载类时加载并解
析类。类一旦被解析,就会以一种线程安全的方式修改原始代码位置以便直接访问静态字段的地址,因为此时已获知该地址。
IBM JIT
编译器中进行了大量的努力以便使用安全而有效率的代码补丁技术,因此在解析类之后,执行的本地代码只加载字段的值,就像编译时已经解析了字段一样。另外一
种方法是生成一些代码,用于在查明字段的位置以前一直检查是否已经解析字段,然后加载该值。对于那些由未解析变成已解析并被频繁访问的字段来说,这种简单
的过程可能带来严重的性能问题。
动态编译的优点
动态地编译 Java 程序有一些重要的优点,甚至能够比静态编译语言更好地生成代码,现代的 JIT 编译器常常向生成的代码中插入挂钩以收集有关程序行为的信息,以便如果要选择方法进行重编译,就可以更好地优化动态行为。
关于此方法的一个很好的例子是收集一个特定 array操作的长度。如果发现每次执行操作时该长度基本不变,则可以为最频繁使用的
array长度生成专门的代码,或者可以调用调整为该长度的代码序列。由于内存系统和指令集设计的特性,用于复制内存的最佳通用例程的执行速度通
常比用于复制特定长度的代码慢。例如,复制 8
个字节的对齐的数据可能需要一到两条指令直接复制,相比之下,使用可以处理任意字节数和任意对齐方式的一般复制循环可能需要 10 条指令来复制同样的 8
个字节。但是,即使此类专门的代码是为某个特定的长度生成的,生成的代码也必须正确地执行其他长度的复制。生成代码只是为了使常见长度的操作执行得更快,
因此平均下来,性能得到了改进。此类优化对大多数静态编译语言通常不实用,因为所有可能的执行中长度恒定的操作比一个特定程序执行中长度恒定的操作要少得
多。
此类优化的另一个重要的例子是基于类层次结构的优化。例如,一个虚方法调用需要查看接收方对象的类调用,以便找出哪个实际目标实现了接收方对象的虚方法。
研究表明:大多数虚调用只有一个目标对应于所有的接收方对象,而 JIT
编译器可以为直接调用生成比虚调用更有效率的代码。通过分析代码编译后类层次结构的状态,JIT
编译器可以为虚调用找到一个目标方法,并且生成直接调用目标方法的代码而不是执行较慢的虚调用。当然,如果类层次结构发生变化,并且出现另外的目标方法,
则 JIT
编译器可以更正最初生成的代码以便执行虚调用。在实践中,很少需要作出这些更正。另外,由于可能需要作出此类更正,因此静态地执行这种优化非常麻烦。
因为动态编译器通常只是集中编译少量的热方法,所以可以执行更主动的分析来生成更好的代码,使编译的回报更高。事实上,大部分现代的
JIT
编译器也支持重编译被认为是热方法的方法。可以使用静态编译器(不太强调编译时间)中常见的非常主动的优化来分析和转换这些频繁执行的方法,以便生成更好
的代码并获得更高的性能。
这些改进及其他一些类似的改进所产生的综合效果是:对于大量的 Java 应用程序来说,动态编译已经弥补了与 C 和 C++ 之类语言的静态本地编译性能之间的差距,在某些情况下,甚至超过了后者的性能。
缺点
但是,动态编译确实具有一些缺点,这些缺点使它在某些情况下算不上一个理想的解决方案。例如,因为识别频繁执行的方法以及编译这些方法需要时间,所以应用
程序通常要经历一个准备过程,在这个过程中性能无法达到其最高值。在这个准备过程中出现性能问题有几个原因。首先,大量的初始编译可能直接影响应用程序的
启动时间。不仅这些编译延迟了应用程序达到稳定状态的时间(想象 Web
服务器经
历一个初始阶段后才能够执行实际有用的工作),而且在准备阶段中频繁执行的方法可能对应用程序的稳定状态的性能所起的作用也不大。如果 JIT
编译会延迟启动又不能显着改善应用程序的长期性能,则执行这种编译就非常浪费。虽然所有的现代 JVM
都执行调优来减轻启动延迟,但是并非在所有情况下都能够完全解决这个问题。
其次,有些应用程序完全不能忍受动态编译带来的延迟。如 GUI 接口之类交互式应用程序就是这样的例子。在这种情况下,编译活动可能对用户使用造成不利影响,同时又不能显着地改善应用程序的性能。
最后,用于实时环境并具有严格的任务时限的应用程序可能无法忍受编译的不确定性性能影响或动态编译器本身的内存开销。
因此,虽然 JIT 编译技术已经能够提供与静态语言性能相当(甚至更好)的性能水平,但是动态编译并不适合于某些应用程序。在这些情况下,Java 代码的提前(Ahead-of-time,AOT)编译可能是合适的解决方案。
AOT Java 编译
大致说来,Java 语言本地编译应该是为传统语言(如 C++ 或
Fortran)而开发的编译技术的一个简单应用。不幸的是,Java 语言本身的动态特性带来了额外的复杂性,影响了 Java
程序静态编译代码的质量。但是基本思想仍然是相同的:在程序执行前生成 Java 方法的本地代码,以便在程序运行时直接使用本地代码。目的在于避免
JIT 编译器的运行时性能消耗或内存消耗,或者避免解释程序的早期性能开销。
挑战
动态类加载是动态 JIT 编译器面临的一个挑战,也是 AOT
编译的一个更重要的问题。只有在执行代码引用类的时候才加载该类。因为是在程序执行前进行 AOT
编译的,所以编译器无法预测加载了哪些类。就是说编译器无法获知任何静态字段的地址、任何对象的任何实例字段的偏移量或任何调用的实际目标,甚至对直接调
用(非虚调用)也是如此。在执行代码时,如果证明对任何这类信息的预测是错误的,这意味着代码是错误的并且还牺牲了 Java 的一致性。
因为代码可以在任何环境中执行,所以类文件可能与代码编译时不同。例如,一个 JVM
实例可能从磁盘的某个特定位置加载类,而后面一个实例可能从不同的位置甚至网络加载该类。设想一个正在进行 bug
修复的开发环境:类文件的内容可能随不同的应用程序的执行而变化。此外,Java 代码可能在程序执行前根本不存在:比如 Java
反射服务通常在运行时生成新类来支持程序的行为。
缺少关于静态、字段、类和方法的信息意味着严重限制了 Java 编译器中优化框架的大部分功能。内联可能是静态或动态编译器应用的最重要的优化,但是由于编译器无法获知调用的目标方法,因此无法再使用这种优化。
内联
内联是一种用于在运行时生成代码避免程序开始和结束时开销的技术,方法是将函数的调用代码插入到调用方的函数中。但是内联最大的益处可能是优化方可见的代码的范围扩大了,从而能够生成更高质量的代码。下面是一个内联前的代码示例:
int foo() { int x=2, y=3; return bar(x,y); }final int bar(int a, int b) { return a+b; }
如果编译器可以证明这个 bar就是 foo()中调用的那个方法,则 bar中的代码可以取代 foo()中对
bar()的调用。这时,bar()方法是 final类型,因此肯定是 foo()中调用的那个方法。甚至在一些虚调用例子中,动态 JIT
编译器通常能够推测性地内联目标方法的代码,并且在绝大多数情况下能够正确使用。编译器将生成以下代码:
int foo() { int x=2, y=3; return x+y; }
在这个例子中,简化前名为值传播的优化可以生成直接返回
5的代码。如果不使用内联,则不能执行这种优化,产生的性能就会低很多。如果没有解析
bar()方法(例如静态编译),则不能执行这种优化,而代码必须执行虚调用。运行时,实际调用的可能是另外一个执行两个数字相乘而不是相加的
bar方法。所以不能在 Java 程序的静态编译期间直接使用内联。
AOT
代码因此必须在没有解析每个静态、字段、类和方法引用的情况下生成。执行时,每个这些引用必须利用当前运行时环境的正确值进行更新。这个过程可能直接影响
第一次执行的性能,因为在第一次执行时将解析所有引用。当然,后续执行将从修补代码中获益,从而可以更直接地引用实例、静态字段或方法目标。
另外,为 Java 方法生成的本地代码通常需要使用仅在单个 JVM 实例中使用的值。例如,代码必须调用 JVM
运行时中的某些运行时例程来执行特定操作,如查找未解析的方法或分配内存。这些运行时例程的地址可能在每次将 JVM 加载到内存时变化。因此 AOT
编译代码需要绑定到 JVM 的当前执行环境中,然后才能执行。其他的例子有字符串的地址和常量池入口的内部位置。
在 WebSphere Real Time 中,AOT 本地代码编译通过 jxeinajar工具(参见图 2)来执行。该工具对 JAR 文件中所有类的所有方法应用本地代码编译,也可以选择性地对需要的方法应用本地代码编译。结果被存储到名为 Java eXEcutable (JXE) 的内部格式中,但是也可轻松地存储到任意的持久性容器中。
您可能认为对所有的代码进行静态编译是最好的方法,因为可以在运行时执行最大数量的本地代码。但是此处可以作出一些权衡。编译的方法越多,代码占用的内存
就越多。编译后的本地代码大概比字节码大 10 倍:本地代码本身的密度比字节码小,而且必须包含代码的附加元数据,以便将代码绑定到 JVM
中,并且在出现异常或请求堆栈跟踪时正确执行代码。构成普通 Java 应用程序的 JAR
文件通常包含许多很少执行的方法。编译这些方法会消耗内存却没有什么预期收益。相关的内存消耗包括以下过程:将代码存储到磁盘上、从磁盘取出代码并装入
JVM,以及将代码绑定到 JVM。除非多次执行代码,否则这些代价不能由本地代码相对解释的性能优势来弥补。
图 2. jxeinajar
跟大小问题相违背的一个事实是:在编译过的方法和解释过的方法之间进行的调用(即编译过的方法调用解释过的方法,或者相反)可能比这两类方法各自内部之间
进行的调用所需的开销大。动态编译器通过最终编译所有由 JIT
编译代码频繁调用的那些解释过的方法来减少这项开销,但是如果不使用动态编译器,则这项开销就不可避免。因此如果是选择性地编译方法,则必须谨慎操作以使
从已编译方法到未编译方法的转换最小化。为了在所有可能的执行中都避免这个问题而选择正确的方法会非常困难。
优点
虽然 AOT 编译代码具有上述的缺点和挑战,但是提前编译 Java 程序可以提高性能,尤其是在不能将动态编译器作为有效解决方案的环境中。
可以通过谨慎地使用 AOT 编译代码加快应用程序启动,因为虽然这种代码通常比 JIT
编译代码慢,但是却比解释代码快很多倍。此外,因为加载和绑定 AOT
编译代码的时间通常比检测和动态编译一个重要方法的时间少,所以能够在程序执行的早期达到那样的性能。类似地,交互式应用程序可以很快地从本地代码中获
益,无需使用引起较差响应能力的动态编译。
RT 应用程序也能从 AOT 编译代码中获得重要的收益:更具确定性的性能超过了解释的性能。WebSphere Real Time
使用的动态 JIT 编译器针对在 RT 系统中的使用进行了专门的调整。使编译线程以低于 RT
任务的优先级操作,并且作出了调整以避免生成带有严重的不确定性性能影响的代码。但是,在一些 RT 环境中,出现 JIT
编译器是不可接受的。此类环境通常需要最严格的时限管理控制。在这些例子中,AOT
编译代码可以提供比解释过的代码更好的原始性能,又不会影响现有的确定性。消除 JIT
编译线程甚至消除了启动更高优先级 RT 任务时发生的线程抢占所带来的性能影响。
优缺点统计
动态(JIT)编译器支持平台中立性,并通过利用应用程序执行的动态行为和关于加载的类及其层次结构的信息来生成高质量的代码。但是
JIT
编译器具有一个有限的编译时预算,而且会影响程序的运行时性能。另一方面,静态(AOT)编译器则牺牲了平台无关性和代码质量,因为它们不能利用程序的动
态行为,也不具有关于加载的类或类层次结构的信息。AOT 编译拥有有效无限制的编译时预算,因为 AOT
编译时间不会影响运行时性能,但是在实践中开发人员不会长期等待静态编译步骤的完成。
表 1 总结了本文讨论的 Java 语言动态和静态编译器的一些特性:
表 1. 比较编译技术
两种技术都需要谨慎选择编译的方法以实现最高的性能。对动态编译器而言,编译器自身作出决策,而对于静态编译器,由开发人员作出选择。让
JIT 编译器选择编译的方法是不是优点很难说,取决于编译器在给定情形中推断能力的好坏。在大多数情况下,我们认为这是一种优点。
因为它们可以最好地优化运行中的程序,所以 JIT 编译器在提供稳定状态性能方面更胜一筹,而这一点在大量的生产 Java
系统中最为重要。静态编译可以产生最佳的交互式性能,因为没有运行时编译行为来影响用户预期的响应时间。通过调整动态编译器可以在某种程度上解决启动和确
定性性能问题,但是静态编译在需要时可提供最快的启动速度和最高级别的确定性。表 2 在四种不同的执行环境中对这两种编译技术进行了比较:
表 2. 使用这些技术的最佳环境
图 3 展示了启动性能和稳定状态性能的总体趋势:
图 3. AOT 和 JIT 的性能对比
使用 JIT 编译器的初始阶段性能很低,因为要首先解释方法。随着编译方法的增多及 JIT
执行编译所需时间的缩短,性能曲线逐渐升高最后达到性能峰值。另一方面,AOT 编译代码启动时的性能比解释的性能高很多,但是无法达到 JIT
编译器所能达到的最高性能。将静态代码绑定到 JVM 实例中会产生一些开销,因此开始时的性能比稳定状态的性能值低,但是能够比使用 JIT
编译器更快地达到稳定状态的性能水平。
没有一种本地代码编译技术能够适合所有的 Java
执行环境。某种技术所擅长的通常正是其他技术的弱项。出于这个原因,需要同时使用这两种编译技术以满足 Java
应用程序开发人员的要求。事实上,可以结合使用静态和动态编译以便提供最大可能的性能提升 —— 但是必须具备平台无关性,它是 Java
语言的主要卖点,因此不成问题。
结束语
本文探讨了 Java 语言本地代码编译的问题,主要介绍了 JIT 编译器形式的动态编译和静态 AOT 编译,比较了二者的优缺点。
虽然动态编译器在过去的十年里实现了极大的成熟,使大量的各种 Java 应用程序可以赶上或超过静态编译语言(如 C++ 或
Fortran)所能够达到的性能。但是动态编译在某些类型的应用程序和执行环境中仍然不太合适。虽然 AOT
编译号称动态编译缺点的万能解决方案,但是由于 Java 语言本身的动态特性,它也面临着提供本地编译全部潜能的挑战。
这两种技术都不能解决 Java 执行环境中本地代码编译的所有需求,但是反过来又可以在最有效的地方作为工具使用。这两种技术可以相互补充。能够恰当地使用这两种编译模型的运行时系统可以使很大范围内的应用程序开发环境中的开发人员和用户受益。