• 《代码阅读方法与实践》读书笔记3


    许多数据结构——如树和堆,操作——如类型推断和类型合一、数学实体——如斐波那契数和分形图,以及算法,如快速排序、树遍历和递归下降分析,都采用递归定义。实体和操作的递归定义用它自身来定义它的对象。虽然这些定义咋看起来好像是无限循环,但实际上并非如此,这是因为基准范例的定义,一般会定义一个特例,他不依赖于递归定义。例如,虽然整数N的阶乘N!,可以定义为N(N-1)!,我们还定义一个基准范例0!=1.

             采用递归定义的算法和数据结构经常用递归的函数定义来实现。

             递归下降分析器——这种方法经常用于分析相对简单的结构,比如命令专有或领域专有的语言、表达式、或基于文本的数据文件。

             打印命令节点并对命令进行分析的这些函数严格说并非递归,这是由于函数体没有语句直接调用包含这些语句的函数。然后,这些函数调用了其他的函数,其他的函数又调用了另外的函数,他们有可能会调用最初的函数。这种类型的递归称为互递归。虽然基于互递归的代码可鞥看起来比简单的递归函数更难理解,但是人们还是能够根据递归定义的底层概念容易地推断出这种类型的递归。

             如果对于函数的所有递归调用恰恰发生在函数返回之前,我们就称该函数是尾递归。尾递归是一个重要的概念,因为编译器可以讲这些调用优化成简单的跳转,因而节省函数调用在时间和内存上的开销。尾递归调用等同于一个回到函数开始处的选婚。程序中有时会用尾递归来代替常规循环。

             异常机制允许程序员将处理错误的代码从代码的正常控制流程中分离出来。在C++和java程序中都会遇到类似的构造;这些语言中用异常处理的一些错误,通过信号报告给C程序。基于异常的错误处理不同于C语言中基于信号的代码,异常作为语言的一部分。能够沿着程序的词法和函数的调用栈传播。允许程序员以结构化的方式处理它们。

             Java的异常处理代码可能包括:

             Try块中的一系列语句,其中发生的异常可以捕获。

             0或多个catch子句,当异常发生时,将和这些子句进行匹配。

             一个可选的finally子句块,总是在try块之后执行。

             Java异常都是java、lang、throwable类的子类产生的对象,java、lang、exception,很多时候,新的异常类都定义为上述两个类的子类。如果一个异常没有在抛出它的方法中被捕获,那么它将会沿着方法的调用栈向上传播给方法的调用者,调用者的调用者,以此类推,知道被捕获为止。

             有些程序并行的执行部分代码,以增强对环境的响应,安排工作的分配,或有效的使用多个计算机或多处理器计算机。这种程序的设计与实现属于一个不断发展的研究领域;

             在硬件层,可能遇到的并行处理类型包括:

             (1)、同一处理器运行多个执行单元

             除非正在编写编译器或汇编器,否则只有在阅读和编写针对某些处理器构架的符号代码时,才会处理这些操作。

             (2)、智能的集成或外部设备

             现代外部设备,如磁盘和磁带驱动器、图形和网络适配器、调制解调器和打印机都有自己的处理器,并能和计算机的主处理器并行地执行高级命令、针对这些设备的代码都由操作系统和设备驱动程序进行分离与抽象。

             (3)、多任务的硬件支持

             大多数现代处理器都提供许多特性,如中断和内存管理硬件,允许操作系统对多个任务进行调度,看起来就如同他们在并行执行。实现这项功能的代码时操作系统的一部分,我们将分析两种常用的软件抽象、进程和线程,这两种抽象都用来封装并行执行的任务。

             (4)、多处理计算机

             (5)、粗粒度分布模型

             在软件层,用来表示代码并行执行,或表面上并行执行的模型如下:

             (1)、进程

             进程是一个操作系统抽象,表示正在运行的程序的单个实例。操作系统使用底层硬件在各个进程之间切换,从而提供对硬件的更有效利用,为复杂系统提供一种结构化机制,同时还使运行环境更为灵活和响应迅速。创建、终止和切换进程都是相对费时的时间;因此,一般倾向于为进程分配大量的工作。进程间的通信与同步由操作系统听的各种机制来处理,比如共享内存对象、信号量和管道。

             (2)、线程

             一个进程可以由多个线程组成;并行运行的控制流程,线程可以在用户层实现,也可以由操作系统提供内在的支持。进程中的所有线程共享许多资源,最重要的是共享全局内存;从而,线程的创建、终止和切换是轻量级的事件,一般倾向于为线程分配一些小型的工作。线程间的通信经常通过使用进程的全局内存来实现,同时使用一些同步原语——如互斥函数,来维护一致性。

             (3)、特别模型

             各种现实或假象的原因都会影响能否使我们前面描述的两种抽象,因此,由于可维护性,效率或无知等原因,一些程序自己实现了对真实或虚拟并行执行的支持。这类程序直接依赖于底层原语。比如:中断、异步信号、轮询、非局部跳转,以及与构架相关的栈操作。

             许多操作系统会在多个处理器上分发进程和线程。出于此因,用于多处理计算机的代码通常围绕进程和线程进行组织。

  • 相关阅读:
    CF821E 【Okabe and El Psy Kongroo】
    BZOJ1231: [Usaco2008 Nov]mixup2 混乱的奶牛
    P1896 [SCOI2005]互不侵犯
    QBXT Day 2 记录
    CF467C George and Job
    【luogu P3373 线段树2】 模板
    【luogu P1306 斐波那契公约数】 题解
    【luogu T24743 [愚人节题目5]永世隔绝的理想乡】 题解
    【luogu P1903 [国家集训队]数颜色】 题解
    莫队算法~讲解
  • 原文地址:https://www.cnblogs.com/SanShaoS/p/5083752.html
Copyright © 2020-2023  润新知