Jekyll2017-12-14T15:30:11+00:00/浴盆的博客欢迎交流前端技术
web信息架构2017-08-22T00:00:00+00:002017-08-22T00:00:00+00:00/blog/2017/08/22/info-architecture<h2 id="信息架构的意义">信息架构的意义</h2>
<p>信息架构指的是</p>
<ul>
<li>共享信息环境的结构化设计。</li>
<li>网站和企业网络的组织系统、标签系统、搜索系统以及导航系统的组合。</li>
<li>创建信息产品和体验的艺术和科学,以提供可用性和可寻性。</li>
</ul>
<h2 id="信息需求">信息需求</h2>
<p>信息需求包括以下几种:</p>
<p>当你想钓到理想中的鱼时,通常你都知道要找的是什么,该以什么名称称呼它,以及上哪儿可以找得到它,这就是所谓的<code class="highlighter-rouge">已知条目搜索</code>(know-item seeking)。例如,你在搜索员工手册、找寻同事电话的时候就是这种情况。</p>
<p>还有一种<code class="highlighter-rouge">探索式搜索</code>(exploratory seeking)。用户并不确定想找的是什么,事实上,无论用户是否了解,他是打算在搜索和浏览的过程中学习某些东西。这种搜索的特点是搜索过程中可能会改变搜索方向,改变学习的信息。</p>
<p>当你每样东西都想要的时候,就是在进行<code class="highlighter-rouge">无遗漏式搜索</code>。用户是打算搜索某一主题的任何信息,每一块石头都想翻一下。</p>
<h2 id="信息搜寻行为">信息搜寻行为</h2>
<p>网站用户都做什么动作寻找信息呢?他们会在搜索系统中输入查询字符串,在链接和链接之间浏览,以及询问别人请求协助(用邮件、聊天软件等)。<code class="highlighter-rouge">搜索</code>、<code class="highlighter-rouge">浏览</code>及<code class="highlighter-rouge">询问</code>都是寻找信息的方法,同时也是信息搜寻行为的基本手段。</p>
<p>搜索行为有两大类:整合和重复。每次对内容的搜索、浏览、询问等,以及交互都会大幅度影响我们正在搜索的东西。</p>
<p>信息搜寻行为中不同组件会组成复杂的模型,比如<code class="highlighter-rouge">采摘模型</code>。用户开始先产生信息需求,然后构想出一个查询。接着,在信息系统中重复动作,可能沿着复杂的路径前进,再沿路取出信息。如果你的用户常常采用采摘模型,你会希望用户在搜索和浏览来来回回的过程变得更加容易。比如雅虎提供这样的整合手段,通过浏览寻找到某个子目录,可以在该子目录内搜索。</p>
<p>另一种有用的模型是<code class="highlighter-rouge">珠形增长</code>。用户从一些有用的文件开始,这些文件正是他们所需要的。他们想更多得到像这样的东西,为了满足这样的需求,google在搜索结果旁放置类似的链接。</p>
<h2 id="信息架构详解">信息架构详解</h2>
<p>信息架构包括这几方面:</p>
<ul>
<li>组织系统。以各种方式向我们展示信息。</li>
<li>导航系统。协助用户在内容上移动。</li>
<li>搜索系统。可让用户搜索内容。</li>
<li>标签系统。使用对用户来说有意义的语言描述分类目录、选项及链接。</li>
</ul>
<p>自上而下的信息架构主要解决以下几类用户的问题:</p>
<ul>
<li>这是哪里。</li>
<li>我知道我要找什么,我要怎么找?</li>
<li>我怎么逛这个网站?</li>
<li>他们想要我发表对网站的意见吗?</li>
<li>我怎么和他人联络?</li>
<li>地址在哪里?</li>
</ul>
<p>所以信息架构针对这些问题,主要解决告诉用户在哪里、协助我们移动到其他关系紧密的网页、协助我们以层级方式和<code class="highlighter-rouge">情境方式</code>在网站内移动、让我们可以操纵内容以便于浏览(筛选)、让我们知道去哪里可以找到基本服务,诸如登入账号和寻求协助。</p>
<h2 id="组织系统">组织系统</h2>
<p>我们对世界的理解多半是取决于组织信息的能力。信息架构作用之一就是通过组织信息,使得他人能够快速找到问题的答案。分类系统的基础是语言,而语言本身是具有模糊性的:字词的理解方式不止一种,每个字词不同的情境下的意义完全不同,这会干扰分类系统的基础。<code class="highlighter-rouge">异质性</code>指的是某种东西或者一群东西是由不相关或不相同的部分所组成的,它的反义词是同质性,即由相似的东西构成。旧式的图书馆卡片目录就是同质性的东西,它用来组织书籍、提供书籍的借还路径,但它却无法提供图书中篇章的数据。而网站大部分是异质性的,既可以组织书籍的借还路径,也可以提供图书中篇章的数据。网站的异质性使得我们很难在内容上强加某种单一的结构化组织系统。</p>
<p>我们每天都会查阅各种组织体系,电话簿、超市以及电视节目表。有些组织体系很容易使用,电话簿中以字母顺序排列的组织体系,很少让我们在找朋友的电话号码时发生困难。网站的组织体系主要有按字母顺序、按时间、按地理位置,还有几种模糊性组织体系,比如按主题、按任务(用户的编辑、评论等操作)、按用户(如今日头条)。</p>
<p>几乎所有优良的信息架构基础都是设计良好的等级式系统或者说分类法,因为等级系统相当有说服力,比如我们会把书分成章,章分成节,节分成段。对网站内容进行分级时,在宽度和深度上的平衡是很重要的,宽度指的是等级系统中每一层的选项数目,深度指的是等级系统中的层数。</p>
<p>数据库模式就是一种自上而下的做法,数据库的定义是:收集和整理数据集合,使能便捷地搜索和获取它们。我们使用的多数数据库都是关系型数据库,数据是存储在一组关系(relation)或表格中。<code class="highlighter-rouge">元数据</code>(下文有定义)是连接信息架构和数据库结构设计的关键所在,元数据可以让我们把关系型数据库的结构和威力,运用到异质性的、非结构化的网站环境中。</p>
<h2 id="标签系统">标签系统</h2>
<p>分类标签(label)的命名是一种表达形式,例如<code class="highlighter-rouge">联系我们</code>就是一种标签,代表一块内容,通常会包括联系人姓名、地址、电话和邮箱等。所以标签的目的是<code class="highlighter-rouge">有效沟通信息</code>,也就是说传递意义时,无需占用太多网页的垂直空间或者说是用户的认知空间(如h1-h6)。标签要有代表性,同时要以用户为中心,行话成分不能太重。</p>
<p>索引术语标签经常被称为关键词、描述性元数据,是一组可以描述任何类型的内容(网站、子网站、网页、内容区块等)的术语标签集合。在我们进行模糊搜索时,就会搜索索引术语相关的数据,即使数据中没有出现该索引术语。索引术语提供了另一种途径观看网站的主要组织结构。</p>
<p>开发标签系统的时候要注意一致性,因为一致性代表的就是可预测性。</p>
<h2 id="导航系统">导航系统</h2>
<p>虽然良好的分类法设计可以减少用户迷路的机会,但是也需要有辅助性的导航工具提供情境以增加灵活性。组织结构与建造房间有关,而导航设计则是增加门窗。导航设计最常遇到的问题是,在移动的灵活性与提供太多选项之间取得平衡。</p>
<p>网站地图的设计对可用性有很大的影响,要了解以下原则:</p>
<ul>
<li>强化信息层次,使得用户对内容的组织方式愈加熟悉。</li>
<li>对了解网站用途的用户,则便利其快速、直接访问内容(比如会员登录后)</li>
<li>避免让用户承担太多信息,目标是协助,不是吓坏用户。</li>
</ul>
<p>指南(guide)的形式有很多种,包括演示之旅、教程,以及针对特定用户、主题或任务而设的网页,主要用来补充现有的浏览和理解网站内容的方法。</p>
<h2 id="搜索系统">搜索系统</h2>
<p>搜索系统有以下要求:</p>
<ul>
<li>为特定用户做索引。根据不同用户群切割建立搜索区域。</li>
<li>以主题做索引。</li>
<li>为新近内容做索引。</li>
</ul>
<p>大部分搜索算法采用模式匹配(pattern matching)的方法,他们会比对用户的查询字符串和网站文件全文的索引。<code class="highlighter-rouge">查全率</code> = 检索出来的相关文件 / 集合中的所有文件。<code class="highlighter-rouge">查准率</code> = 检索出来的相关文件 / 集合中的相关文件。搜索工具可以提供自动词干搜索功能,把一个术语扩展,包含其他共享相同词干的术语。还有拼写检查工具。</p>
<h2 id="元数据">元数据</h2>
<p>对数据处理而言,元数据是一种用于定义的数据,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。可以理解为数据说明,比如HTML中的meta标签。</p>
<h2 id="受控词表">受控词表</h2>
<p>受控词表是一系列精心选择的词汇和短语,这些词汇和短语用于对各种各样的信息单位(文档或作品)加以标记,以便更加简便地通过搜索而获取到这些信息单位。通过确保仅仅采用一条权威术语来描述每个概念以及受控词表之中的每条权威术语仅仅描述一个概念,受控词表解决的是有关同形异义词、同义词和多义词的问题。简而言之,受控词表有助于减少正常人类语言内在所固有的歧义问题,从而保证一致性。受控词表是一组自然语言的子集,或者说一份等价术语(equivalent term)清单,按同义词环圈的形式排列,或者是一份优选术语清单,储存在规范文档中。</p>信息架构的意义 信息架构指的是大型网站架构2017-08-14T00:00:00+00:002017-08-14T00:00:00+00:00/blog/2017/08/14/website-architecture<h2 id="大型网站架构">大型网站架构</h2>
<p>为了解决大型网站面临的高并发访问、海量数据处理、高可靠运行等一系列问题与挑战,大型互联网公司在实践中提出了许多解决方案,以实现网站高性能、高可用、易伸缩、可扩展、安全等各种技术架构目标。这些解决方案又被更多网站重复使用,从而逐渐形成大型网站架构模式。<code class="highlighter-rouge">分层</code>是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。分层结构在计算机世界中无处不在,网络的 7层通信协议是一种分层结构;计算机硬件、操作系统、应用软件也可以看作是一种分层结构。在大型网站架构中也采用分层结构,将网站软件系统分为<code class="highlighter-rouge">应用层</code>(负责具体业务和视图展示,如网站首页及搜索输入和结果展示)、<code class="highlighter-rouge">服务层</code>(为应用层提供服务支持,如用户管理服务,购物车服务等)、<code class="highlighter-rouge">数据层</code>(提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等)。通过分层,可以更好地将一个庞大的软件系统切分成不同的部分,便于分工合作开发和维护;各层之间具有一定的独立性。</p>
<h2 id="分割">分割</h2>
<p>如果说分层是将软件在横向方面进行切分,那么分割就是在纵向方面对软件进行切分。大型网站分割的粒度可能会很小。比如在应用层,将不同业务进行分割,例如将购物、论坛、搜索、广告分割成不同的应用,由独立的团队负责,部署在<code class="highlighter-rouge">不同服务器</code>上;在同一个应用内部,如果规模庞大业务复杂,会继续进行分割,比如购物业务,可以进一步分割成机票酒店业务、3C 业务, 小商品业务等更细小的粒度。</p>
<h2 id="分布式">分布式</h2>
<p>对于大型网站,分层和分割的一个主要目的是为了切分后的模块便于分布式部署,即将不同模块 部署在不同的服务器上,通过远程调用协同工作。分布式意味着可以使用更多的计算机完成同样的功能,计算机越多,CPU、内存、存储资源也就越多,能够处理的并发访问和数据量就越大,进而能够为更多的用户提供服务。但分布式在解决网站高并发问题的同时也带来了其他问题。首先,分布式意味着服务调用必须<code class="highlighter-rouge">通过网络</code>,这可能会对性能造成比较严重的影响;其次,服务器越多,服务器宕机的概率也就越大。
常用的分布式方案有以下几种:</p>
<ul>
<li>分布式应用和服务:将分层和分割后的应用和服务模块分布式部署,除了可以改善网站性能和并发性、加快开发和发布速度、减少数据库连接资源消耗外;还可以使不同应用复用共同的服务,便于业务功能扩展。</li>
<li>分布式静态资源:网站的静态资源如 JS,CSS,Logo 图片等资源独立分布式部署,并采用独立的域名,即人们常说的动静分离。静态资源分布式部署可以减轻应用服务器的负载压力;通过使用独 立域名加快浏览器并发加载的速度;</li>
<li>分布式数据和存储:大型网站需要处理以 P 为单位的海量数据,单台计算机无法提供如此大的存储空间,这些数据需要分布式存储。除了对传统的关系数据库进行分布式部署外,为网站应用而生的 各种 NoSQL产品几乎都是分布式的。</li>
<li>分布式计算:严格说来,应用、服务、实时数据处理都是计算,网站除了要处理这些在线业务,还有很大一部分用户没有直观感受的后台业务要处理,包括搜索引擎的索引构建、数据仓库的数据分析统计等。这些业务的计算规模非常庞大,目前网站普遍使用 Hadoop及其MapReduce分布式计算框架进行此类批处理计算,其特点是移动计算而不是移动数据,将计算程序分发到数据所在的位置以加速计算和分布式计算。</li>
</ul>
<h2 id="集群">集群</h2>
<p>使用分布式虽然已经将分层和分割后的模块独立部署,但是对于用户访问集中的模块(比如网站首页),还需要将独立部署的服务器集群化,即多台服务器部署相同应用构成一个集群,通过负载均衡设备共同对外提供服务。因为服务器集群有更多服务器提供相同服务,因此可以提供更好的并发特性,当有更多用户访问的时候,只需要向集群中加入新的机器即可。同时因为一个应用由多台服务器提供,当某台服务器发生故障时,负载均衡设备或者系统的失效转移机制会将请求转发到集群中其他服务器上,使服务器故 障不影响用户使用。所以在网站应用中,<code class="highlighter-rouge">即使是访问量很小的分布式应用和服务,也至少要部署两台服务器构成一个小的集群,目的就是提高系统的可用性</code>。</p>
<h2 id="缓存">缓存</h2>
<p>缓存就是将数据存放在距离计算最近的位置以加快处理速度。缓存是改善软件性能的第一手段,现代CPU越来越快的一个重要因素就是使用了更多的缓存,在复杂的软件设计中,缓存几乎无处不在。大型网站架构设计在很多方面都使用了缓存设计。</p>
<ul>
<li>CDN:即内容分发网络,部署在距离终端用户最近的网络服务商,用户的网络请求总是先到达他的网络服务商那里,在这里缓存网站的一些静态资源(较少变化的数据),可以就近以最快速度返回 给用户,如视频网站和门户网站会将用户访问量大的热点内容缓存在CDN。</li>
<li>反向代理:反向代理属于网站前端架构的一部分,部署在网站的前端,当用户请求到达网站的数据中心时,最先访问到的就是反向代理服务器,这里缓存网站的静态资源,无需将请求继续转发给应用服务器就能返回给用户。</li>
<li>本地缓存:在应用服务器本地缓存着热点数据,应用程序可以在本机内存中直接访问数据,而无需访问数据库。</li>
<li>分布式缓存:大型网站的数据量非常庞大,即使只缓存一小部分,需要的内存空间也不是单机能 承受的,所以除了本地缓存,还需要分布式缓存,将数据缓存在一个专门的分布式缓存集群中,应用 程序通过网络通信访问缓存数据。</li>
</ul>
<p>使用缓存有两个前提条件,一是数据访问热点不均衡,某些数据会被更频繁的访问,这些数据应该放在缓存中;二是数据在某个时间段内有效,不会很快过期,否则缓存的数据就会因已经失效而产生脏读,影响结果的正确性。网站应用中,缓存除了可以加快数据访问速度,还可以减轻后端应用和数据存储的负载压力,这一点对网站数据库架构至关重要,网站数据库几乎都是按照有缓存的前提进行负载能力设计的。</p>
<h2 id="异步">异步</h2>
<p>计算机软件发展的一个重要目标和驱动力是降低软件耦合性。事物之间直接关系越少,就越少被彼此影响,越可以独立发展。大型网站架构中,系统解耦合的手段除了前面提到的分层、分割、分布等,还有一个重要手段是异步,业务之间的消息传递不是同步调用,而是将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作。
在单一服务器内部可通过多线程共享内存队列的方式实现异步,处在业务操作前面的线程将输出写入到队列,后面的线程从队列中读取数据进行处理;在分布式系统中,多个服务器集群通过分布式 消息队列实现异步,分布式消息队列可以看作内存队列的分布式部署。</p>
<h2 id="冗余">冗余</h2>
<p>网站需要7*24小时连续运行,但是服务器随时可能出现故障,特别是服务器规模比较大时,出现某台服务器宕机是必然事件。要想保证在服务器宕机的情况下网站依然可以继续服务,不丢失数据, 就需要一定程度的服务器冗余运行,数据冗余备份,这样当某台服务器宕机时,可以将其上的服务和数据访问转移到其他机器上。访问和负载很小的服务也必须部署至少两台服务器构成一个集群,其目的就是通过冗余实现服务高可用。</p>
<h2 id="自动化">自动化</h2>
<p>在无人值守的情况下网站可以正常运行,一切都可以自动化是网站的理想状态。目前大型网站的自动化架构设计主要集中在发布运维方面。发布对网站都是头等大事,许多网站故障出在发布环节,网站工程师经常加班也是因为发布不顺利。通过减少人为干预,使发布过程自动化可有效减少故障。发布过程包括诸多环节。自动化代码管理,代码版本控制、代码分支创建合并等过程自动化,开发工程师只要提交自己参与开发的产品代号,系统就会自动为其创建开发分支,后期会自动进行代码合并;自动化测试,代码开发完成,提交测试后,系统自动将代码部署到测试环境,启动自动化测试用例进行测试,向相关人员发送测试报告,向系统反馈测试结果。</p>
<h2 id="安全">安全</h2>
<p>网站在安全架构方面也积累了许多模式:通过密码和手机校验码进行身份认证;登录、交易等操作需要对网络通信进行加密,网站服务器上存储的敏感数据如用户信息等也进行加密处理;为了防止机器人程序滥用网络资源攻击网站,网站使用验证码进行识别;对于常见的用于攻击网站的XSS攻击、SQL注入、进行编码转换等相应处理; 对于垃圾信息、敏感信息进行过滤;对交易转账等重要操作根据交易模式和交易信息进行风险控制。</p>
<h2 id="高性能架构">高性能架构</h2>
<p>两个网站性能架构设计方案:A 方案和 B 方案,A 方案在小于100个并发用户访问时,每个请求的响应时间是1秒,当并发请求达到200的时候,请求的响应时间将骤增到 10 秒。B方案不管是100个并发用户访问还是200个并发用户访问,每个请求的响应时间都差不多是1.5秒。哪个方案的性能好?网站性能是客观的指标,可以具体体现到响应时间、吞吐量等技术指标,同时也是主观的感受。
不同视角下的网站性能有不同的标准,也有不同的优化手段。从用户角度,网站性能就是用户在浏览器上直观感受到的网站响应速度快还是慢。用户感受到的时间,包括用户计算机和网站服务器通信的时间、网站服务器处理的时间、用户计算机浏览器构造请求解析响应数据的时间。开发人员关注的主要是应用程序本身及其相关子系统的性能,包括响应延迟、系统吞吐量、并发 处理能力、系统稳定性等技术指标。主要的优化手段有使用缓存加速数据读取,使用集群提高吞吐能力,使用异步消息加快请求响应及实现削峰,使用代码优化手段改善程序性能。运维人员更关注基础设施性能和资源利用率,如网络运营商的带宽能力、服务器硬件的配置、数据中心网络架构、服务器和网络带宽的资源利用率等。</p>
<h2 id="性能测试指标">性能测试指标</h2>
<p>不同视角下有不同的性能标准,不同的标准有不同的性能测试指标,从开发和测试人员的视角,网站性能测试的主要指标有响应时间、并发数、吞吐量、性能计数器等。</p>
<ul>
<li>响应时间。指应用执行一个操作需要的时间,包括从发出请求开始到收到最后响应数据所需要的时间。响应 时间是系统最重要的性能指标,直观地反映了系统的“快慢”。测试程序通过模拟应用程序,记录收到响应和发出请求之间的时间差来计算系统响应时间。但是记录及获取系统时间这个操作也需要花费一定的时间,如果测试目标操作本身需要花费的时间极少,比如几微秒,那么测试程序就无法测试得到系统的响应时间。实践中通常采用的办法是重复请求,比如一个请求操作重复执行一万次,测试一万次执行需要的总响应时间之和,然后除以一万,得到单次请求的响应时间。</li>
<li>并发数。指系统能够同时处理请求的数目,这个数字也反映了系统的负载特性。对于网站而言,并发数即网站并发用户数,指同时提交请求的用户数目。现实中,经常看到某些网站,特别是电商类网站,市场推广人员兴致勃勃地打广告打折促销,用户兴致勃勃地去抢购,结果活动刚一开始,就因为并发用户数超过网站最大负载而响应缓慢,急性子 的用户不停刷新浏览器,导致系统并发数更高。</li>
<li>吞吐量。指单位时间内系统处理的请求数量,体现系统的整体处理能力。对于网站,可以用“请求数/秒” 或是“页面数/秒”来衡量,也可以用“访问人数/天”或是“处理的业务数/小时”等来衡量。TPS(每秒事务数)是吞吐量的一个常用量化指标,此外还有 HPS(每秒 HTTP 请求数)、QPS(每秒查询数)等。系统吞吐量和系统并发数,以及 响应时间的关系可以形象地理解为高速公路的通行状况:吞吐量是每天通过收费站的车辆数目(可以换算成收费站收取的高速费),并发数是高速公路上的正在行驶的车辆数目,响应时间是车速。车辆很少时,车速很快,但是收到的高速费也相应较少;随着高速公路上车辆数目的增多,车速略受影响,但是收到的高速费增加很快;随着车辆的继续增加,车速变得 越来越慢,高速公路越来越堵,收费不增反降;如果车流量继续增加,超过某个极限后,任何偶然因素都会导致高速全部瘫痪,车走不动,费当然也收不着,而高速公路成了停车场( 资源耗尽)。</li>
<li>性能计数器是描述服务器或操作系统性能的一些数据指标。包括System Load、对象与线程数、内存使用、CPU使用、磁盘与网络 I/O 等指标。这些指标也是系统监控的重要参数,对这些指标设置报警阈值,当监控系统发现性能计数器超过阈值时,就向运维和开发人员报警,及时发现处理系统异常。</li>
</ul>
<h2 id="性能测试方法">性能测试方法</h2>
<p>性能测试是一个总称,具体可细分为性能测试、负载测试、压力测试、稳定性测试。</p>
<ul>
<li>性能测试是以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能预期。</li>
<li>负载测试是对系统不断地增加并发请求以增加系统压力,直到系统的某项或多项性能指标达到安全临界值, 如某种资源已经呈饱和状态,这时继续对系统施加压力,系统的处理能力不但不能提高,反而会下降。</li>
<li>压力测试是<code class="highlighter-rouge">超过安全负载</code>的情况下,对系统继续施加压力,直到系统崩溃或不能再处理任何请求,以此获得系统最大压力承受能力。</li>
<li>稳定性测试是被测试系统在特定硬件、软件、网络环境条件下,给系统加载一定业务压力,使系统运行一段较长时间,以此检测系统是否稳定。在不同生产环境、不同时间点的请求压力是不均匀的,呈波浪特性, 因此为了更好地模拟生产环境,稳定性测试也应不均匀地对系统施加压力。</li>
</ul>大型网站架构 为了解决大型网站面临的高并发访问、海量数据处理、高可靠运行等一系列问题与挑战,大型互联网公司在实践中提出了许多解决方案,以实现网站高性能、高可用、易伸缩、可扩展、安全等各种技术架构目标。这些解决方案又被更多网站重复使用,从而逐渐形成大型网站架构模式。分层是企业应用系统中最常见的一种架构模式,将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。分层结构在计算机世界中无处不在,网络的 7层通信协议是一种分层结构;计算机硬件、操作系统、应用软件也可以看作是一种分层结构。在大型网站架构中也采用分层结构,将网站软件系统分为应用层(负责具体业务和视图展示,如网站首页及搜索输入和结果展示)、服务层(为应用层提供服务支持,如用户管理服务,购物车服务等)、数据层(提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等)。通过分层,可以更好地将一个庞大的软件系统切分成不同的部分,便于分工合作开发和维护;各层之间具有一定的独立性。计算机科学导论2017-08-02T00:00:00+00:002017-08-02T00:00:00+00:00/blog/2017/08/02/computer-science<h2 id="图灵模型">图灵模型</h2>
<p>在讨论图灵模型之前,我们将计算机定义为一个数据处理器,可以认为他是一个接收输入数据、处理数据并产生输出数据的黑盒。图灵模型增加了一个额外元素——程序。输出数据依赖两方面内容:输入数据与程序,无论哪个改变,都会导致输出数据改变。</p>
<p>
冯诺依曼模型
-
基于这个模型构造的计算机分为4个子系统:存储器、算术逻辑单元、控制单元、输入/输出单元。存储器用来存储<code class="highlighter-rouge">程序和数据</code>,控制单元是对存储器、算术逻辑单元和输入/输出单元进行控制操作的单元。冯诺依曼模型中要求程序必须存储在内存中,<code class="highlighter-rouge">数据和程序</code>都是以位模式(0和1序列)存储在内存中。
冯诺依曼模型中的一段程序由一组数量有限的指令组成,控制单元从内存中提取一条指令,解释指令,接着执行指令。指令按照顺序执行,当然指令可以请求控制单元以便跳转到后面的指令执行。</p>
<h2 id="计算机组成">计算机组成</h2>
<p>计算机由三部分组成:计算机硬件、软件和数据。当前计算机硬件基于冯诺依曼模型。</p>
<p>
数字系统
-
数字系统定义了如何用独特的符号来表示一个数字,在不同系统中,数字有不同的表示方式。比如十进制系统(以10为底,每个位数对底数相乘,可以表示整数和小数)、二进制、八进制和十六进制。这些进制之间的转换,可以使用连乘法或者连除法对整数和小数部分进行处理。</p>
<p>
数据存储
-
数据以不同的形式出现,如数字、文字、音频和视频。所有外部的数据类型的数据都采用统一的数据表示法转换之后存入计算机中,当数据从计算机输出时再还原回来。这种通用的模式称为位模式。<code class="highlighter-rouge">位</code>(bit)是存储在计算机中的最小单位,它是0或者1。为了表示不同的数据类型,应该使用位模式,长度为8的位模式被称为一个<code class="highlighter-rouge">字节</code>(byte)。为占用较少的空间,数据在存储到计算机中之前通常会被压缩。</p>
<p> 无符号整数就是没有符号的整数,它介于0到无穷大之间,通常计算机都定义一个最大无符号数的常量,称为最大无符号数,它的值是2的n次方减一。通常我们先把一个整数转化成二进制,如果二进制位数不足n位,则在左边补0。当要存储的整数的位数大于n位,就会发生溢出。无符号整数表示法可以提高存储效率,因为不用存储符号位,很多场景中使用无符号整数,如<code class="highlighter-rouge">寻址</code>(地址从0到存储器总字节),为<code class="highlighter-rouge">其他数据类型排序</code>等。相对地,有符号数可以通过符号位+绝对值来表示,但是几乎所有计算机都是使用<code class="highlighter-rouge">二进制补码</code>来存储有符号整数。有两种方法来处理小数点:<code class="highlighter-rouge">定点</code>和<code class="highlighter-rouge">浮点</code>。</p>
<h2 id="存储文本">存储文本</h2>
<p>在任何语言中,文本片段都是该语言中某种意义的一个符号。我们可以用位模式表达任何一个符号。现在问题是,在一种语言中,位模式到底需要多少位来表示一个符号?这主要取决于该语言集中有多少符号。位模式长度和符号之间是对数关系,如果需要2个符号,位模式长度为是1位。不同<code class="highlighter-rouge">位模式集合</code>被设计用于表示文本符号,比如ASCII和unicode。unicode的不同部分被分配用于表示不同语言的符号。如今ASCII已经成为unicode的一部分。</p>
<h2 id="存储音频">存储音频</h2>
<p>音频是模拟数据的例子,当我们讨论用计算机存储声音时,我们是说存储一个音频信号的密度。如果我们不能记录一段间隔内的音频信号的所有值,至少可以记录其中的一些,采样意味着我们在模拟信号上选择数量有限的点来度量他们的值并记录下来,每秒40 000个样本的采样率对音频信号来说是足够好的。这意味着我们可能要为每一秒的样本存储40 000个真实的值,为每个样本使用一个无符号数会更简便。编码的主流标准是MP3,它采用每秒44 100个样本以及每样本16位,再使用人耳无法识别的方法进行压缩。</p>
<h2 id="存储图像">存储图像</h2>
<p>存储在计算机中的图像使用两种不同的技术:<code class="highlighter-rouge">光栅图</code>或<code class="highlighter-rouge">矢量图</code>。当我们需要存储图像时,就用到了光栅图,一张照片由模拟数据组成,类似于音频信息,不同的是数据密度随着空间而变化,而不是因时间而变化。这种情况下采样通常被称作扫描,样本称为像素。<code class="highlighter-rouge">解析度</code>指的是对于每英寸的方块线条需要记录多少像素,如果解析度够高,人眼中不会出现图像的不连续。<code class="highlighter-rouge">色彩深度</code>用于表示像素的位的数量,对颜色的感觉是我们的眼睛如何对光线的响应。光栅图有两个缺点:即文件尺寸太大和重新调整图像大小有麻烦,放大光栅图因为着放大像素,放大的图像看上去很粗糙。<code class="highlighter-rouge">矢量图</code>编码并不存储每个像素的位模式,一个图像被分解成几何图形的组合,例如:线段、矩形或圆形。当要显示或打印图像时,把图像的尺寸作为输入传给系统,系统依照相同的公式画出图像,矢量图不适合存储照片图像的细微精妙。</p>
<h2 id="存储视频">存储视频</h2>
<p>视频是图像在时间上的表示(称为帧)。我们只需要将图像转换成一系列位模式并储存,这些图像组合起来就可表示视频。</p>
<h2 id="逻辑运算">逻辑运算</h2>
<p>逻辑运算指的是应用于同个模式下的二进制位,或在两个模式下的二进位的运算。位层次上的运算包括非运算、或运算、与运算和异或运算。模式层次上的运算就是将上述逻辑运算应用到n位中,<code class="highlighter-rouge">移位运算</code>通过移动模式中的位,使它们能向左移动或向右移动,分为逻辑移位运算和算术移位运算。逻辑移位运算用于无符号数,在n位模式中,逻辑右移代表最右位被丢弃,最左边填充0.循环移位表示没有位被丢弃,形成一个环。算术移位是用二进制补码表示的无符号数,算术右移被用来对整数除以2.</p>
<h2 id="计算机组成-1">计算机组成</h2>
<p>中央处理单元(CPU)用于数据的运算。它有三个组成部分,算术逻辑部分(CLU)、控制单元、寄存器。<code class="highlighter-rouge">算术逻辑单元(CLU)</code>对数据进行逻辑、移位和算术运算(加减乘除)。寄存器分为数据寄存器、指令寄存器和程序计算器。数据寄存器用来存储输入数据和运算结果,计算机在CPU中使用十几个寄存器来提高运算速度。CPU的主要职责是从内存中逐条地取出指令,并将取出的指令存储在指令寄存器中,解释并执行命令。CPU计数器是程序计数器,程序计数器中保存着当前正在执行的指令。CPU的第三个部分是<code class="highlighter-rouge">控制单元</code>,控制单元控制各个子系统的操作,通过从控制单元发送到其他子系统的信号进行。</p>
<p><code class="highlighter-rouge">主存储器</code>是计算机的第二个主要子系统,它是存储单元的集合,每一个存储单元都有唯一的表示,称为<code class="highlighter-rouge">地址</code>。数据以称为字的位组的方式在内存中传入和传出,字可以是8位,16位,32位,甚至是64位。在存储器上存取每个字都需要相应的标识符,尽管程序员通过命名的方式来区分字,但在硬件层次从上,每个字都是通过地址来标识的。存储器的类型主要有两种,RAM和ROM。<code class="highlighter-rouge">随机存取寄存器</code>(RAM)是计算机主存中的主要组成部分,RAM可读可写,但是断电后就丢失,ROM的内容是由制造商写进去的,用户只能读但是不能写,它的优点是非易失性。计算机用户需要许多的存储器,有其是速度快且价格低廉的存储器,但是这样的存储器通常不便宜,因此需要一种折中的办法,解决办法是采用存储器的层次结构,当对速度要求很严苛的时候使用少量高速存储器,用适量的中速存储器存储经常需要访问的数据,用大量的低速存储器存储不常访问的数据,主存就属于这一类。</p>
<p>计算机的第三个子系统是IO子系统,可以分为存储设备和非存储设备。两个最常见的非存储设备是键盘与显示器。存储设备可以存储大量的信息以备后用,他们比主存便宜得多,断电信息也不会丢失。</p>
<p>CPU和内存之间通常由称为总线的三组线路连接在一起,他们分别是:数据总线、地址总线和控制总线。IO设备不能直接与连接CPU和内存的总线相连,需要通过中介器件。</p>
<h2 id="程序执行">程序执行</h2>
<p>CPU通过重复的<code class="highlighter-rouge">机器周期</code>来执行指令程序中指令,一个简化的周期包括3步:取指令、译码和执行。在取指令阶段,控制单元系统将下一条要执行的指令复制到CPU的指令寄存器,被复制的指令的地址被保存在程序计数器中,复制完成后,计数器将自动加1,指向下一条指令的内存地址。机器周期的第二个阶段是译码阶段,当指令置于指令寄存器后,该指令将由控制单元负责译码,指令译码的结果是产生一系列系统可以执行的二进制代码。指令译码完毕后,控制单元发送任务命令到CPU的某个部件,这就是执行。</p>
<p>计算机通过命令将数据从IO设备传输到CPU和内存,因此IO设备的运行速度要比CPU慢得多,因此CPU和IO设备之间需要同步,有三种方法可以进行同步:程序控制输入/输出,中断控制输入/输出,直接存储器存取。在程序控制输入/输出中,采用最简单的一种同步:CPU等待IO设备,CPU中和IO设备的数据传输是通过程序中的指令实现的,当收到传输指令,CPU停止工作直到数据传输结束为止,CPU不断查询IO驱动器状态,如果设备做好传输准备,那么数据将被传到CPU。中断控制输入/输出是CPU收到传输指令后没有停止工作,当IO设备准备好时,它通知(中断)CPU。第三种方法是直接存储器读取(DMA),CPU发信息给DMA,这些信息包括传输类型(输入或输出),内存起始地址以及传输字节数,由DMA作为CPU代理。</p>
<h2 id="网络">网络</h2>
<p>网络是硬件和软件的组合,它把数据从一个地方发到另一个地方。链路是数据从一个设备到另一个设备的通信通道,为了进行通信,两个设备必须使用某种方式连接到同一个链路。术语物理拓扑是指网络在物理上的布置方式,网络的拓扑是所有链路和设备间关系的几何表示。TCP/IP协议包括多层,应用层允许用户访问网络,它提供对电子邮件,远程文件访问和传输、浏览万维网的支持。传输层负责整个消息的进程到进程的传输——建立客户到服务器的传输层的逻辑通信,服务器的IP地址对于传输是必须的,另外我们需要另一个地址来标识服务器进程,这称为端口号,服务器进程使用众所周知的端口号,而客户端进程使用传输层指定的临时端口号。传输层的一个职责是多路复用和解多路复用,可以类比为邮递员将邮件交给门卫分发给住户。传输层同时负责拥塞控制和流量控制。网络层负责单个数据包从源主机到目的主机的发送,网络层的主协议是因特网协议(IP),当前版本是IPv4,但IPv6也在使用(ip数更多)。数据链路层负责数据帧的节点到节点的发送(用数据帧封装数据包,在包头增加路由器的链路层地址)。物理层完成在物理介质上传输二进制流所需要的功能,在数据链路层上传送的单元是帧,而物理层传输的是二进制位(把位转成信号)。</p>图灵模型 在讨论图灵模型之前,我们将计算机定义为一个数据处理器,可以认为他是一个接收输入数据、处理数据并产生输出数据的黑盒。图灵模型增加了一个额外元素——程序。输出数据依赖两方面内容:输入数据与程序,无论哪个改变,都会导致输出数据改变。 冯诺依曼模型 - 基于这个模型构造的计算机分为4个子系统:存储器、算术逻辑单元、控制单元、输入/输出单元。存储器用来存储程序和数据,控制单元是对存储器、算术逻辑单元和输入/输出单元进行控制操作的单元。冯诺依曼模型中要求程序必须存储在内存中,数据和程序都是以位模式(0和1序列)存储在内存中。 冯诺依曼模型中的一段程序由一组数量有限的指令组成,控制单元从内存中提取一条指令,解释指令,接着执行指令。指令按照顺序执行,当然指令可以请求控制单元以便跳转到后面的指令执行。前端性能统计2017-07-23T00:00:00+00:002017-07-23T00:00:00+00:00/blog/2017/07/23/performance<h2 id="前端性能统计">前端性能统计</h2>
<p>网站的速度影响了用户访问网站最初的体验。试想,如果一个用户,在等待了若干秒后,还是停留在白屏的状态,那么他的选择将是离开这个网站。性能统计有助于帮我们检测网站的用户体验。<br />
那么网站都有哪些指标?</p>
<ul>
<li><code class="highlighter-rouge">首屏时间</code>。指一个网站被浏览器如IE窗口上的区域被充满所需时间。其实就是网页刚进入时,渲染完整个浏览器屏幕的时间。关于是否包含首屏所有的图片下载完成。这个网上有些争议,另一种说法是只要DOM+样式 都渲染完了,就算完成了。Chrome的Network可以清晰看到这个过程。</li>
<li><code class="highlighter-rouge">白屏时间</code>,页面处于空白的时间,通常影响白屏时间的多数是:DNS解析耗时+服务端耗时+网络传输耗时。(当然可能因为头部js阻塞页面影响)</li>
<li><code class="highlighter-rouge">用户可操作时间</code>。一般来讲<code class="highlighter-rouge">domready</code>时间,便是我们的用户可操作时间了。</li>
<li><code class="highlighter-rouge">总下载时间</code>, 页面总体的下载时间,所有的页面资源都下载完成。(window.onload)</li>
</ul>
<h2 id="如何统计这些指标">如何统计这些指标</h2>
<p>当然我们可以自己打开控制台,在页面的各个阶段,将时间打印出来,或者使用HTML5新增的接口:<code class="highlighter-rouge">performance</code>来进行评估。正常我们需要一个监控程序,去时刻提醒,现在网站的速度处于什么状况。所以,在代码中,增加统计,并把统计结果发送到服务器。在服务器采集这些日志,并产生一个监控的网站。</p>
<h2 id="如何统计首屏时间">如何统计首屏时间</h2>
<p>对于网页高度小于屏幕的网站来说,统计首屏时间非常的简单,因为我们已经可以从performance中得到渲染开始时<code class="highlighter-rouge">performance.timing.navigationStart</code>,只要在页面底部加上脚本打印当前时间即可(比如<code class="highlighter-rouge">http://localhost:8091/?action=speedlog</code>)。
</p>
<h2 id="使用缓存优化">使用缓存优化</h2>
<p>除了304缓存之外,如果html/css/js一直不变,可以考虑直接缓存到客户端。我们把不变的js/css/html存储到<code class="highlighter-rouge">localstorage</code>中去,下次加载首页的时候。在特定的位置,不必再从服务端请求。我们在写入localstorage的时候,同时在cookie中种下当前所有要缓存的内容的版本(<code class="highlighter-rouge">MD5戳</code>)就可以。如果cookie中有version,证明种过cookie,写过local,所以,不用传内容了,直接传script就好了,如果没有就要传输并且写入。</p>
<h2 id="使用iconfont">使用iconfont</h2>
<p>如果有一些业务不需要多彩色图的时候,iconfont就派上了用场,在满足UE高清的需求下,可以节省大量的资源。</p>
<h2 id="极小的图片base64化">极小的图片base64化</h2>
<p>对于小于1k的图片,我们将其变为base64编码,并融入到css中,一起换存到localstorage中去,这样即节省了网络请求,同时使图片也可以缓存到local中去了。</p>前端性能统计 网站的速度影响了用户访问网站最初的体验。试想,如果一个用户,在等待了若干秒后,还是停留在白屏的状态,那么他的选择将是离开这个网站。性能统计有助于帮我们检测网站的用户体验。 那么网站都有哪些指标? 首屏时间。指一个网站被浏览器如IE窗口上的区域被充满所需时间。其实就是网页刚进入时,渲染完整个浏览器屏幕的时间。关于是否包含首屏所有的图片下载完成。这个网上有些争议,另一种说法是只要DOM+样式 都渲染完了,就算完成了。Chrome的Network可以清晰看到这个过程。 白屏时间,页面处于空白的时间,通常影响白屏时间的多数是:DNS解析耗时+服务端耗时+网络传输耗时。(当然可能因为头部js阻塞页面影响) 用户可操作时间。一般来讲domready时间,便是我们的用户可操作时间了。 总下载时间, 页面总体的下载时间,所有的页面资源都下载完成。(window.onload) 如何统计这些指标 当然我们可以自己打开控制台,在页面的各个阶段,将时间打印出来,或者使用HTML5新增的接口:performance来进行评估。正常我们需要一个监控程序,去时刻提醒,现在网站的速度处于什么状况。所以,在代码中,增加统计,并把统计结果发送到服务器。在服务器采集这些日志,并产生一个监控的网站。 如何统计首屏时间 对于网页高度小于屏幕的网站来说,统计首屏时间非常的简单,因为我们已经可以从performance中得到渲染开始时performance.timing.navigationStart,只要在页面底部加上脚本打印当前时间即可(比如http://localhost:8091/?action=speedlog)。 使用缓存优化 除了304缓存之外,如果html/css/js一直不变,可以考虑直接缓存到客户端。我们把不变的js/css/html存储到localstorage中去,下次加载首页的时候。在特定的位置,不必再从服务端请求。我们在写入localstorage的时候,同时在cookie中种下当前所有要缓存的内容的版本(MD5戳)就可以。如果cookie中有version,证明种过cookie,写过local,所以,不用传内容了,直接传script就好了,如果没有就要传输并且写入。前端可用性2017-07-21T00:00:00+00:002017-07-21T00:00:00+00:00/blog/2017/07/21/usage-of-front-end<h2 id="前端可用性">前端可用性</h2>
<p>前端服务的可用性分为三个部分</p>
<ul>
<li>前端代码可用性(测试质量,线上异常)</li>
<li>静态资源服务可用性</li>
<li>网络链路可用性
即从业务后台服务网上,一直到用户界面,一切都是前端服务。</li>
</ul>
<h2 id="如何衡量前端服务可用性">如何衡量前端服务可用性</h2>
<p>前端服务的可用性衡量和后端衡量方法类似,只考虑<code class="highlighter-rouge">存在故障的时长</code>。可用性指标不是为了让我们通过复杂算法来计算影响,而是为了激励我们再可观测范围内做到没有问题。影响用户数,影响订单数,影响GMV(Gross Merchandise Volume,订单总额)等指标更多的是用于事故定级。</p>
<h2 id="哪里容易出问题">哪里容易出问题</h2>
<ul>
<li>前端代码可用性:1.空指针问题。2.<code class="highlighter-rouge">业务逻辑覆盖率</code>,在复杂的业务项目中,逻辑混乱交错,逻辑环境<code class="highlighter-rouge">难以模拟</code>,进而容易在逻辑处理上产生疏忽。3.<code class="highlighter-rouge">兼容性</code>问题,要面临的环境很多,包括平台、系统版本、浏览器版本、webview版本,Hybrid桥版本等。</li>
<li>静态资源服务可用性:1. 前端静态资源服务链的稳定性,例如Nginx,Node等。2.CDN并不是任何时候都可以正常提供服务,可能会遇到SSL证书链问题等。</li>
<li>网络链路可用性:DNS劫持是一个麻烦问题,大部分运营商为了节省跨省流量结算费用而进行DNS劫持,走内部的缓存。</li>
</ul>
<h2 id="解决方案">解决方案</h2>
<ul>
<li>技术选型要简单稳健,核心链路上的代码要减少外部依赖。举个例子,当一个应用涉及的视图跳转和数据传递太多时,单页应用比多页更具优势。而在SPA选型的时候,React,ng等一线框架可以选,但如果这个SPA应用中单个视图中的复杂度并不高,可以遇到的性能瓶颈并不多的时候,并不需要像React、ng这样更适合复杂大型单页应用的框架。如果使用自己封装的框架,我们就拥有更强的<code class="highlighter-rouge">源码维护能力</code>,这对于核心业务是非常必须的。</li>
<li>前端工程化的兴起导致大家会把所有文件打包到一个js文件中,HTML中只有js的引用,这样就导致HTML下载之后还是白屏。这时就用到了SSR(服务端渲染),通用做法是增加一个Node层,在服务器端做首屏内容的拼接。或者使用预编译渲染,在编译期间把首屏结构全部拼装好。</li>
<li>空指针部分只能从语言本身解决,比如使用TypeScript,在编码过程中过滤掉空指针问题。</li>
<li>兼容性问题主要通过平台搭建,做到快速在多机型上进行核心流程回归测试。</li>
<li>解决DNS劫持只能通过使用HTTPS,并且要保证该域名不能被HTTP访问以免运营商进行DNS劫持。(使用HTTPS之后,如果运营商的缓存服务器没有SSL证书将会请求失败)</li>
</ul>
<p> </p>前端可用性 前端服务的可用性分为三个部分 前端代码可用性(测试质量,线上异常) 静态资源服务可用性 网络链路可用性 即从业务后台服务网上,一直到用户界面,一切都是前端服务。 如何衡量前端服务可用性 前端服务的可用性衡量和后端衡量方法类似,只考虑存在故障的时长。可用性指标不是为了让我们通过复杂算法来计算影响,而是为了激励我们再可观测范围内做到没有问题。影响用户数,影响订单数,影响GMV(Gross Merchandise Volume,订单总额)等指标更多的是用于事故定级。编程语言实现模式(1)2017-07-19T00:00:00+00:002017-07-19T00:00:00+00:00/blog/2017/07/19/language-implementation-patterns<h2 id="语言读取">语言读取</h2>
<p>语言读取是这样一个过程:文件读取部分对输入内容进行“识别”,并输出数据结构作为中间表示(intermediate representation,IR),供其他部件使用。流水线的末端是生成器,会根据IR及之前收集信息进行计算,并输出最终结果。</p>
<p>把输入内容用IR的形式放到内存以后,就可以从中抽取信息或者修改它,第一步要做的就是<code class="highlighter-rouge">遍历IR</code>。要想输出有用的输出结果,就必须<code class="highlighter-rouge">分析输入内容</code>,对于一个字符x,我们需要知道它是一个变量,还是一个方法,要知道它的类型以及定义位置。</p>
<h2 id="识别式子结构">识别式子结构</h2>
<p> 例如,<code class="highlighter-rouge">return x+1</code>这个由词法单元组成的小式子就是表达式。我们可以把x+1看做一个<code class="highlighter-rouge">expr</code>,整个return语句归类为一个<code class="highlighter-rouge">returnstat</code>,同时语句也是一个<code class="highlighter-rouge">stat</code>。将其翻转,就能得到解析树。</p>
<h2 id="构建递归下降语法解析器">构建递归下降语法解析器</h2>
<p> 解析器用来解析识别的解析树,解析器不必构造具体的解析树,因为只要为解析中的指定子结构(树的内节点)编写专用的函数,就能得到解析树的信息。</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="err"> </span><span class="c1">//对于return x + 1</span>
<span class="err"> </span><span class="k">void</span> <span class="nx">stat</span><span class="p">(){</span> <span class="nx">returnstat</span><span class="p">()</span> <span class="p">};</span>
<span class="k">void</span> <span class="nx">returnstat</span><span class="p">(){</span> <span class="nx">match</span><span class="p">(</span><span class="s2">"return"</span><span class="p">);</span> <span class="nx">expr</span><span class="p">();</span> <span class="nx">match</span><span class="p">(</span><span class="s2">";"</span><span class="p">);</span> <span class="p">}</span>
<span class="k">void</span> <span class="nx">expr</span><span class="p">(){</span> <span class="nx">match</span><span class="p">(</span><span class="s2">"x"</span><span class="p">);</span><span class="nx">match</span><span class="p">(</span><span class="s2">"+"</span><span class="p">);</span><span class="nx">match</span><span class="p">(</span><span class="s2">"1"</span><span class="p">);</span> <span class="p">}</span>
</code></pre></div></div>语言读取 语言读取是这样一个过程:文件读取部分对输入内容进行“识别”,并输出数据结构作为中间表示(intermediate representation,IR),供其他部件使用。流水线的末端是生成器,会根据IR及之前收集信息进行计算,并输出最终结果。 把输入内容用IR的形式放到内存以后,就可以从中抽取信息或者修改它,第一步要做的就是遍历IR。要想输出有用的输出结果,就必须分析输入内容,对于一个字符x,我们需要知道它是一个变量,还是一个方法,要知道它的类型以及定义位置。 识别式子结构 例如,return x+1这个由词法单元组成的小式子就是表达式。我们可以把x+1看做一个expr,整个return语句归类为一个returnstat,同时语句也是一个stat。将其翻转,就能得到解析树。 构建递归下降语法解析器 解析器用来解析识别的解析树,解析器不必构造具体的解析树,因为只要为解析中的指定子结构(树的内节点)编写专用的函数,就能得到解析树的信息。 //对于return x + 1 void stat(){ returnstat() }; void returnstat(){ match("return"); expr(); match(";"); } void expr(){ match("x");match("+");match("1"); }新博客来啦!!2017-07-18T00:00:00+00:002017-07-18T00:00:00+00:00/blog/2017/07/18/new-blog<p>2017年7月以前的博客:<a href="http://blog.csdn.net/sysuzhyupeng" title="old blog">old blog</a></p>
<p>这是我的github: <a href="https://github.com/sysuzhyupeng" title="github">github</a></p>
<p>谢谢大家的支持,我会更加努力。</p>2017年7月以前的博客:old blog