精华内容
下载资源
问答
  • SQL执行过程

    千次阅读 2018-10-10 09:40:20
    工业编码sql是不可或缺的,编写或优化出高效率的SQL是码农的重要工作,了解SQL的处理过程可以让我们与数据库交互时游刃有余。下面是oracle数据库处理SQL的过程。 SQL处理 SQL处理是SQL语句的解析、优化、行源生成...

    工业编码中sql是不可或缺的,编写或优化出高效率的SQL是码农的重要工作,了解SQL的处理过程可以让我们与数据库交互时游刃有余。下面是oracle数据库处理SQL的过程。

    SQL处理

    SQL处理是SQL语句的解析、优化、行源生成和执行。为了更快的处理数据,数据库会做一些缓存,从而省略这些阶段中的一些。
    下图描述了SQL处理的一般阶段。
    在这里插入图片描述

    SQL解析

    解析阶段包括将SQL语句段分割成其他例程可以处理的数据结构。数据库在应用程序指示时解析语句,这意味着只有应用程序而不是数据库本身可以减少解析次数。
    当应用程序发出SQL语句时,应用程序对数据库发出一个解析调用,以准备执行语句。解析调用打开或创建游标,该游标是一个会话级别的保存特定解析SQL语句和其他处理信息的私有SQL区域的句柄。私有SQL区域包括SQL相关的信息:变量的值,查询执行的状态信息和执行的区域。游标和私有SQL区域在程序全局区域(PGA)中。
    在解析调用期间,数据库执行以下检查:

    语法检查:语法是否有效

    SQL> SELECT * FORM employees;
    SELECT * FORM employees
             *
    ERROR at line 1:
    ORA-00923: FROM keyword not found where expected
    

    语义检查:语句是否有意义,例如,语句中的表和列是否存在。

    SQL> SELECT * FROM nonexistent_table;
    SELECT * FROM nonexistent_table
                  *
    ERROR at line 1:
    ORA-00942: table or view does not exist
    

    共享池检查

    前面的检查标识在语句执行之前可以找到的错误。有些错误不能通过解析来捕获。例如,数据库只能在语句执行期间遇到数据转换中的死锁或错误。
    在解析过程中,数据库执行共享池检查,以确定它是否可以跳过语句处理的资源密集型步骤。
    为此,数据库使用哈希算法来为每个SQL语句生成哈希值。语句哈希值是在V$SQL.SQL_ID。这个哈希值在Oracle整个数据库的版本中是确定的,
    因此在单个实例或不同实例中的相同语句具有相同的SQL_ID。
    当用户提交SQL语句时,数据库搜索共享SQL区域(SGA),以查看现有的解析语句是否具有相同的哈希值。

    SQL语句的哈希值与下列值不同:

    语句的内存地址
    Oracle数据库使用SQL_ID在查找表中执行键控读取。这样,数据库就可以获得语句的可能内存地址。
    语句的执行计划的哈希值
    SQL语句在共享池中可以有多个计划。通常,每个计划都有不同的哈希值。如果相同的SQL_ID具有多个计划哈希值,则数据库知道该SQL_ID存在多个计划。

    根据提交的语句类型和哈希检查的结果,解析操作分为以下类别:

    硬解析:DDL总是会执行硬解析

    如果Oracle数据库不能重用现有代码,那么它必须构建一个新的可执行版本的应用程序代码。此操作称为硬解析或类库缓存缺失。
    在硬解析过程中,数据库多次访问库缓存和数据字典缓存,以检查数据字典。当数据库访问这些区域时,它使用被调用对象上的闩锁的序列化设备(并发访问中保护SGA中的共享数据结构),这样它们的定义不会改变。锁存争用会增加语句执行时间并减少并发性。

    软解析

    软解析是任何解析而不是硬解析的语法。如果提交的语句与共享池中的可重用SQL语句相同,则Oracle数据库重用现有代码。代码的重用也被称为库缓存命中。
    软解析可以根据它们执行的工作量而变化。例如,配置会话共享SQL区域有时可以减少软解析中的锁存量,使它们更加“软”。
    一般来说,软解析优于硬解析,因为数据库跳过优化和行源生成步骤,直接执行。
    在这里插入图片描述
    如果检查确定共享池中的语句具有相同的哈希值,则数据库执行语义和环境检查,以确定语句是否具有相同的含义。相同的语法是不够的,例如两个schema中创建同名的表,就不能复用,必须进行硬解析。在这种情况下,优化器环境是可以影响执行计划生成的会话设置的总体性,例如工作区大小或优化器设置(例如,优化器模式)。考虑由单个用户执行的以下SQL语句序列

    ALTER SESSION SET OPTIMIZER_MODE=ALL_ROWS;
    ALTER SYSTEM FLUSH SHARED_POOL;               # optimizer environment 1
    SELECT * FROM sh.sales;
    ALTER SESSION SET OPTIMIZER_MODE=FIRST_ROWS;  # optimizer environment 2
    SELECT * FROM sh.sales;
    ALTER SESSION SET SQL_TRACE=true;             # optimizer environment 3
    SELECT * FROM sh.sales;
    

    在三个不同的优化器环境中执行相同的SELECT语句。因此,数据库为这些语句创建三个单独的共享SQL区域,并迫使每个语句进行硬解析。

    SQL优化

    在优化阶段,Oracle数据库必须对每一个唯一的DML语句执行至少一次的硬解析,并在该解析过程中执行优化。
    数据库从不优化DDL,除非它包括一个DML组件,如需要优化的子查询。

    SQL行源生成

    行源生成器是从优化器接收最优执行计划并生成可由数据库其余部分使用的迭代执行计划的软件。执行计划(execution plan)是行源生成器的输出。
    迭代计划是一个二进制程序,当由SQL引擎执行时,生成结果集。该计划采取的步骤组合的形式。每个步骤返回行集。下一步要么使用这个集合中的行,要么最后一步将行返回给发出SQL语句的应用程序。
    行源是由执行计划中的步骤返回的行集,以及可以迭代处理行的控制结构。行源可以是连接或分组操作的表、视图或结果。
    行源生成器生成行源树,该行源树是行源的集合。行源树显示以下信息:
    语句引用的表的排序
    语句中提到的每个表的访问方法
    语句中联接操作影响的表的联接方法
    数据操作,如过滤、排序或聚合

    SQL执行

    在执行过程中,SQL引擎执行行源生成器生成的树中的每一行源。此步骤是DML处理中唯一的强制步骤。
    在执行过程中,如果数据不在内存中,则数据库从磁盘读取数据到内存。数据库还取出确保数据完整性所需的任何锁和锁存器,并记录SQL执行期间所做的任何更改。
    处理SQL语句的最后阶段是关闭游标。

    SELECT e.last_name, j.job_title, d.department_name 
    FROM   hr.employees e, hr.departments d, hr.jobs j
    WHERE  e.department_id = d.department_id
    AND    e.job_id = j.job_id
    AND    e.last_name LIKE 'A%';
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 975837011
    --------------------------------------------------------------------------------
    | Id| Operation                     | Name        |Rows|Bytes|Cost(%CPU)|Time  |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT              |             |  3 | 189 | 7(15)| 00:00:01 |
    |*1 |  HASH JOIN                    |             |  3 | 189 | 7(15)| 00:00:01 |
    |*2 |   HASH JOIN                   |             |  3 | 141 | 5(20)| 00:00:01 |
    | 3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |  3 |  60 | 2 (0)| 00:00:01 |
    |*4 |     INDEX RANGE SCAN          | EMP_NAME_IX |  3 |     | 1 (0)| 00:00:01 |
    | 5 |    TABLE ACCESS FULL          | JOBS        | 19 | 513 | 2 (0)| 00:00:01 |
    | 6 |   TABLE ACCESS FULL           | DEPARTMENTS | 27 | 432 | 2 (0)| 00:00:01 |
    --------------------------------------------------------------------------------
    

    在这里插入图片描述

    Oracle数据库如何处理DML

    大多数DML语句都有查询组件。在查询中,光标的执行将查询的结果放入一组称为结果集的行中。

    如何获取行集

    结果集行可以一次取一行,也可以成组取一行。
    在提取阶段,数据库选择行,如果查询请求,则命令行。每个连续的FETCH检索结果的另一行,直到最后一行被提取为止。
    通常,数据库无法确定查询所要检索的行数,直到获取最后一行为止。Oracle数据库响应于fetch调用检索数据,以便数据库读取的行越多,它执行的工作就越多。对于某些查询,数据库尽可能快地返回第一行,而对于其他查询,则在返回第一行之前创建整个结果集。

    读一致性

    一般来说,查询通过使用Oracle数据库读取一致性机制来检索数据,这保证了查询读取的所有数据块都与单个时间点一致。
    读取一致性使用撤消数据来显示过去版本的数据。例如,假设查询必须在全表扫描中读取100个数据块。查询处理前10个块,而在不同会话中的DML修改块75。当第一个会话到达块75时,它实现了更改,并使用撤消数据来检索旧的、未修改的数据版本,并在内存中构建块75的非当前版本。

    数据变化

    必须更改数据的DML语句使用读取一致性来检索仅在修改开始时匹配搜索标准的数据。
    之后,这些语句在当前状态下检索数据块并进行必要的修改。数据库必须执行与修改数据相关的其他操作,例如生成重做和撤消数据。

    Oracle数据库如何处理DDL

    Oracle数据库处理DDL与DML不同。
    例如,当创建表时,数据库不会优化CREATETABLE语句。相反,Oracle数据库解析DDL语句并执行命令。
    数据库处理DDL的方式不同,因为它是在数据字典中定义对象的一种手段。通常,Oracle数据库必须解析并执行许多递归SQL语句来执行DDL语句。假设您创建一个表如下:
    CREATE TABLE mytable (mycolumn INTEGER);
    通常,数据库将运行几十个递归语句来执行前面的语句。递归SQL将执行如下操作:

      在创建CREATETABLE语句之前发出提交
      验证用户权限是否足以创建表
      确定表应该驻留在哪个表空间中
      确保尚未超过表空间配额
      确保架构中没有对象具有相同的名称
      将定义表的行插入到数据字典中
      如果DDL语句成功或如果没有回滚,则发出提交。
    

    小结

    	现有连接 ---用户进程 执行SQL操作
    	传递给服务器进程的PGA --处理SQL操作 --- 分析任务 ---语法 语义 共享检查
    	---到SGA的共享池
    	
    	SGA的共享池 ---查询优化器操作 ---数据buffer data buffer cache ---datafile 
    	---得到行数据---行数据是否需要再次处理--需要再次处理的--交给PGA处理 
    	---返回服务器进程---结果传输到用户进程 ---用户看到执行结果。
    	
    	SGA的共享池 ---查询优化器操作 ---数据buffer data buffer cache ---datafile 
    	---得到行数据---行数据是否需要再次处理--不需要再次处理的
    	---返回给服务器进程---结果传输到用户进程 ---用户看到执行结果。
    

    官方原文

    oracle doc

    展开全文
  • python执行过程

    千次阅读 2019-01-12 09:10:37
    [说说Python程序的执行过程] 1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在。如果是解释型语言,那么...

    [说说Python程序的执行过程]

    1. Python是一门解释型语言?

    我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在。如果是解释型语言,那么生成的*.pyc文件是什么呢?c应该是compiled的缩写才对啊!

    为了防止其他学习Python的人也被这句话误解,那么我们就在文中来澄清下这个问题,并且把一些基础概念给理清。

    2. 解释型语言和编译型语言

    计算机是不能够识别高级语言的,所以当我们运行一个高级语言程序的时候,就需要一个“翻译机”来从事把高级语言转变成计算机能读懂的机器语言的过程。这个过程分成两类,第一种是编译,第二种是解释。

    编译型语言在程序执行之前,先会通过编译器对程序执行一个编译的过程,把程序转变成机器语言。运行时就不需要翻译,而直接执行就可以了。最典型的例子就是C语言。

    解释型语言就没有这个编译的过程,而是在程序运行的时候,通过解释器对程序逐行作出解释,然后直接运行,最典型的例子是Ruby。

    通过以上的例子,我们可以来总结一下解释型语言和编译型语言的优缺点,因为编译型语言在程序运行之前就已经对程序做出了“翻译”,所以在运行时就少掉了“翻译”的过程,所以效率比较高。但是我们也不能一概而论,一些解释型语言也可以通过解释器的优化来在对程序做出翻译时对整个程序做出优化,从而在效率上超过编译型语言。

    此外,随着Java等基于虚拟机的语言的兴起,我们又不能把语言纯粹地分成解释型和编译型这两种。

    用Java来举例,Java首先是通过编译器编译成字节码文件,然后在运行时通过解释器给解释成机器文件。所以我们说Java是一种先编译后解释的语言。

    再换成C#,C#首先是通过编译器将C#文件编译成IL文件,然后在通过CLR将IL文件编译成机器文件。所以我们说C#是一门纯编译语言,但是C#是一门需要二次编译的语言。同理也可等效运用到基于.NET平台上的其他语言。

    3. Python到底是什么

    其实Python和Java/C#一样,也是一门基于虚拟机的语言,我们先来从表面上简单地了解一下Python程序的运行过程吧。

    当我们在命令行中输入python hello.py时,其实是激活了Python的“解释器”,告诉“解释器”:你要开始工作了。可是在“解释”之前,其实执行的第一项工作和Java一样,是编译。

    熟悉Java的同学可以想一下我们在命令行中如何执行一个Java的程序:

    javac hello.java

    java hello

    只是我们在用Eclipse之类的IDE时,将这两部给融合成了一部而已。其实Python也一样,当我们执行python hello.py时,他也一样执行了这么一个过程,所以我们应该这样来描述Python,Python是一门先编译后解释的语言。

    4. 简述Python的运行过程

    在说这个问题之前,我们先来说两个概念,PyCodeObject和pyc文件。

    我们在硬盘上看到的pyc自然不必多说,而其实PyCodeObject则是Python编译器真正编译成的结果。我们先简单知道就可以了,继续向下看。

    当python程序运行时,编译的结果则是保存在位于内存中的PyCodeObject中,当Python程序运行结束时,Python解释器则将PyCodeObject写回到pyc文件中。

    当python程序第二次运行时,首先程序会在硬盘中寻找pyc文件,如果找到,则直接载入,否则就重复上面的过程。

    所以我们应该这样来定位PyCodeObject和pyc文件,我们说pyc文件其实是PyCodeObject的一种持久化保存方式。

    5. 运行一段Python程序

    我们来写一段程序实际运行一下:

    img201205140014.jpg

    程序本身毫无意义。我们继续看:

    201205140015.jpg

    然而我们在程序中并没有看到pyc文件,仍然是test.py孤零零地呆在那!

    那么我们换一种写法,我们把print_str方法换到另外的一个python模块中:

    201205140015.jpg

    201205140016.jpg

    然后运行程序:

    201205140016.jpg

    这个时候pyc文件出现了,其实认真思考一下不难得到原因,我们考虑一下实际的业务情况。

    6. pyc的目的是重用

    回想本文的第二段在解释编译型语言和解释型语言的优缺点时,我说编译型语言的优点在于,我们可以在程序运行时不用解释,而直接利用已经“翻译”过的文件。也就是说,我们之所以要把py文件编译成pyc文件,最大的优点在于我们在运行程序时,不需要重新对该模块进行重新的解释。

    所以,我们需要编译成pyc文件的应该是那些可以重用的模块,这于我们在设计软件类时是一样的目的。所以Python的解释器认为:只有import进来的模块,才是需要被重用的模块。

    这个时候也许有人会说,不对啊!你的这个问题没有被解释通啊,我的test.py不是也需要运行么,虽然不是一个模块,但是以后我每次运行也可以节省时间啊!

    OK,我们从实际情况出发,思考下我们在什么时候才可能运行python xxx.py文件:

    A. 执行测试时。

    B. 开启一个Web进程时。

    C. 执行一个程序脚本。

    我们逐个来说,第一种情况我们就不用多说了,这个时候哪怕所有的文件都没有pyc文件都是无所谓的。

    第二种情况,我们试想一个webpy的程序把,我们通常这样执行:

    201205140016.jpg

    抑或者:

    201205140017.jpg

    然后这个程序就类似于一个守护进程一样一直监视着8181/9002端口,而一旦中断,只可能是程序被杀死,或者其他的意外情况,那么你需要恢复要做的是把整个的Web服务重启。那么既然一直监视着,把PyCodeObject一直放在内存中就足够了,完全没必要持久化到硬盘上。

    最后一个情况,执行一个程序脚本,一个程序的主入口其实很类似于Web程序中的Controller,也就是说,他负责的应该是Model之间的调度,而不包含任何的主逻辑在内,如我在http://www.cnblogs.com/kym/archive/2010/07/19/1780407.html中所提到,Controller应该就是一个Facade,无任何的细节逻辑,只是把参数转来转去而已,那么如果做算法的同学可以知道,在一段算法脚本中,最容易改变的就是算法的各个参数,那么这个时候给持久化成pyc文件就未免有些画蛇添足了。

    所以我们可以这样理解Python解释器的意图,Python解释器只把我们可能重用到的模块持久化成pyc文件。

    7. pyc的过期时间

    说完了pyc文件,可能有人会想到,每次Python的解释器都把模块给持久化成了pyc文件,那么当我的模块发生了改变的时候,是不是都要手动地把以前的pyc文件remove掉呢?

    当然Python的设计者是不会犯这么白痴的错误的。而这个过程其实就取决于PyCodeObject是如何写入pyc文件中的。

    我们来看一下import过程的源码吧:

    201205140024.jpg

    这段代码比较长,我们只来看我标注了的代码,其实他在写入pyc文件的时候,写了一个Long型变量,变量的内容则是文件的最近修改日期,同理,我们再看下载入pyc的代码:

    201205140025.jpg

    201205140026.jpg

    不用仔细看代码,我们可以很清楚地看到原理,其实每次在载入之前都会先检查一下py文件和pyc文件保存的最后修改日期,如果不一致则重新生成一份pyc文件。

    8. 写在最后的

    其实了解Python程序的执行过程对于大部分程序员,包括Python程序员来说意义都是不大的,那么真正有意义的是,我们可以从Python的解释器的做法上学到什么,我认为有这样的几点:

    A. 其实Python是否保存成pyc文件和我们在设计缓存系统时是一样的,我们可以仔细想想,到底什么是值得扔在缓存里的,什么是不值得扔在缓存里的。

    B. 在跑一个耗时的Python脚本时,我们如何能够稍微压榨一些程序的运行时间,就是将模块从主模块分开。(虽然往往这都不是瓶颈)

    C. 在设计一个软件系统时,重用和非重用的东西是不是也应该分开来对待,这是软件设计原则的重要部分。

    D. 在设计缓存系统(或者其他系统)时,我们如何来避免程序的过期,其实Python的解释器也为我们提供了一个特别常见而且有效的解决方案。

    转载

    展开全文
  • 递归过程中语句执行顺序

    千次阅读 2018-08-13 17:56:34
    //递归的过程中在"递"的过程中解决问题 function function_name(Max_argument){ if(end_condition){ end; }else{ solve; function_name(Min_argument);//问题规模逐渐减小 } } 注:...

    递归的两种模式

    模式一

    //递归的过程中在"递"的过程中解决问题
    function function_name(Max_argument){
        if(end_condition){
            end;
        }else{
            solve;
            function_name(Min_argument);//问题规模逐渐减小
        }
    }

    注:位于递归函数前的语句和函数具有顺序性

    模式二

    //递归的过程中在"归"的过程中解决问题
    function function_name(Max_argument){
        if(end_condition){
            end;
        }else{
            function_name(Min_argument);//问题规模逐渐减小
            solve;
        }
    }

    注:位于递归函数后的语句的执行顺序与原顺序相反;
    每一级的递归调用都拥有自己当前的局部变量,所以当调用对象的时候应该注意是调用对象的非引用(复制对象), 以避免修改子对象造成对主问题的影响

    调用栈

    调用栈:描述函数之间的调用关系,当函数之间相互调用的时候会使用调用栈;
    调用栈由多个栈帧组成,每个栈帧记录着一个未运行完的函数; 栈帧中保存着该函数的返回地址以及局部变量;
    在递归中,递归函数的每一次的”递进去”,栈帧都会将上个函数的返回地址局部变量保存以便在返回的过程中找得到相应的”回归出来的方向”

    通过一个简单的例子说明上述调用顺序问题

    //10进制转2进制
    void f(int n){
        if(n==0)
            return;
        printf("%d",n%2);//模式1,该模式下输出语句将会是顺序调用
        f(n/2)
    }
    //n=4,将输出001,整个过程中先调用printf语句,然后"递进去",通过栈帧进行回归操作最终返回至main函数
    
    
    
    void f(int n){
        if(n==0)
            return;
        f(n/2)
        printf("%d",n%2)
    //模式2,整个过程中先执行f 函数进行递归,到达递归基时返回执行printf
    //整个过程中就是通过栈帧来记录返回过程应该执行的printf,形成"回归出来"解决问题,最终返回至main函数
    //n=4,输出100
    }

    接下来将用斐波那契查找作为典型的例子证明尾递归的重要性:
    看下面的一个错误的例子:

    #include<iostream>
    using namespace std;
    int find(int a[],int lo,int hi,int e){
        int mid=(hi+lo)/2;
        if(e==a[mid]) return mid;
        if(e<a[mid]) {
            cout<<"lo_1="<<lo<<endl;
            find(a,lo,mid-1,e);
        }
        if(e>a[mid]){ 
            find(a,mid+1,hi,e);
            cout<<"lo_2="<<lo<<endl;
        }
        if(lo>hi) {
            cout<<"lo_3="<<lo<<endl;
         return 0;  
        }
    
    
    } 
    int main(){//0,1,2,3,4,5,6,7,8,9 ,10,11,12,13,14,15,16,17 
        int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
        cout<<find(a,0,17,18);
        return 0;
    }
    //斐波那契查找
    这个例子证明了尾递归的重要,当前出现的问题是在递归过程中返回值具有随机性,为正确将值返回,记住一条
    //递归过程中栈帧的调用,到达递归基的时候返回出正确结果,但是经过栈帧的调用后,正确的返回值返回给上一层调用函数,上一层函数中未寻找到正确的值
    //无法返回出正确的值,则返回出去一个随机的值,导致最后答案错误, 正确的做法是将递归过程改为尾递归(return find(....)),直接终止程序(将后续的语句执行停止)
    //就此返回出去的值只能是递归基时产生的值(每一层程序终止后所对应的栈帧被清除,最后只保留着递归基中的栈帧) 
    //原本打算采用else处理,不用return改为尾递归,但是失败了,因为栈栈的缘故,每层的栈帧未清除,并且返回过程中没有满足条件的语句导致没有返回值,最终无法
    //完成尾递归的操作 
    //唉, 理解了递归过程,但是还未深刻理解尾递归的含义,莫大的悲哀,导致出现不该出现的错误 

    针对上述的操作进行修改

    //斐波那契查找
    /* 
    #include<iostream>
    using namespace std;
    int f[]={0,1,1,2,3,5,8,13,21,34}; 
    //       0 1 2 3 4 5 6 7 8 9 10 
    int find(int a[],int lo,int hi,int e){
        int k=0;
        while((hi-lo)>f[k]) {//斐波那契数列确定当前的黄金分割点
            k++;
        //  cout<<"k"<<k<<endl;
        } 
        int mid=lo+f[k-2]-1;//在中点求值出现错误,未正确表示中点位置 
    //  int mid=(lo+hi)>>1; 
        if(lo>=hi) {return 0;}//未命中目标
        if(e==a[mid]) return mid;
        if(e<a[mid]) {return    find(a,lo,mid-1,e);}
        if(e>a[mid]) {return    find(a,mid+1,hi,e);}
    } 
    int main(){//0,1,2,3,4,5,6,7,8,9 ,10,11,12,13,14,15,16,17 
        int a[]={1,2,3,4,5,6,7,8,9};
        cout<<find(a,0,9,8);
        return 0;
    } 

    递归过程调用栈的使用与调用其他函数没有区别,每一次的函数调用将会形成新的栈帧以保存上一次函数的返回地址和局部变量, 当栈帧中函数体执行完成时将会删除栈帧,处理返回值并修改当前代码行
    来自别人的话_很赞同__递归函数尽量不要有返回值或者基本类型的返回值(直接尾递归),如果要求必须有复杂类型返回值,写成两个函数,递归函数不要有返回值,只是在函数中改变复杂类型的值;在驱动程序中定义复杂类型,调用递归函数返回复杂类型

    展开全文
  • CPU内部组成结构及指令执行过程

    万次阅读 多人点赞 2015-05-15 09:53:16
    计算机的基本硬件系统由运算器、控制器、存储器和输入、... CPU通过执行指令来控制程序的执行顺序,这是CPU的重要职能。  (2)操作控制  一条指令功能的实现需要若干个操作信号来完成,CPU产生每条指令的操作信号并

      计算机的基本硬件系统由运算器、控制器、存储器和输入、输出设备五大部件组成。运算器和控制器等部件被集成在一起统称为中央处理单元(Central Processing Unit,CPU)。

      CPU的功能

      (1)程序控制

      CPU通过执行指令来控制程序的执行顺序,这是CPU的重要职能。

      (2)操作控制

      一条指令功能的实现需要若干个操作信号来完成,CPU产生每条指令的操作信号并将操作信号送往不同的部件,控制相应的部件按指令的功能要求进行操作。

      (3)时间控制

      CPU对各种操作进行时间上的控制,这就是时间控制。CPU对每条指令的整个执行过程要进行严格控制,即指令执行过程中操作信号的出现时间、持续时间及出现的时间顺序都需要进行严格控制。

      (4)数据处理

      CPU通过对数据进行算术运算及逻辑运算等方式进行加工处理,数据加工处理的结果被人们所利用。所以,对数据的加工处理也是CPU最根本的任务。

      CPU的组成

      CPU主要有运算器、控制器、寄存器组合内部总线等部件组成。

      运算器

      运算器由算术逻辑单元(Arithmetic and Logic Unit,ALU),累加寄存器(AC),数据缓冲寄存器(DR),和状态条件寄存器组成,它是数据加工处理部件,完成计算机的各种算术和逻辑运算。相对于控制器而言,运算器接受控制器的命令而进行动作,即运算器所进行的全部操作都是由控制器发出的控制信号来指挥的,所以它是执行部件。

      算术逻辑单元(ALU)

      ALU是运算器的重要组成部件,负责处理数据,实现对数据的算术运算和逻辑运算。

      累计寄存器(AC)

      AC通常简称为累计器,它是一个通用寄存器,其功能是当运算器的算术逻辑单元执行算术或逻辑运算时,为ALU提供一个工作区。最后的运算结果放到AC中,因此运算器中至少有一个累加寄存器。

      数据缓冲寄存器(DR)

      在对内部存储器进行读写操作时,用DR暂时存放由内存储器读写的一条指令或一个数据字,将不同时间段内读写的数据隔离开来。DR作为CPU和内存、外部设备之间的数据传送中转站;作为CPU和内存、外围设备之间在操作速度上的缓冲;在单累加器结构的运算器中,DR还可以件作为操作数寄存器。

      状态条件寄存器(PSW)

      PSW保存由算术指令和逻辑指令运行或测试的结果建立的各种条件码内容,主要分为状态标志和控制标志。这些标志通常由一位触发器保存,保存了当前指令执行完成之后的状态。通常一个算术操作产生一个运算结果,一个逻辑操作产生一个判决。

      控制器

      运算器只能完成运算,而控制器用于控制整个CPU的工作,他决定了计算机运行过程的自动化。它不仅要保证程序的正确执行,而且要能够处理异常事件。控制器一般包括指令控制逻辑、时序控制逻辑、总线控制逻辑和中断控制逻辑等几个部分。

      时序控制逻辑要为每条指令按时间顺序提供应有的控制信号。总线逻辑是为多个功能部件服务的信息通路控制电路。中断控制逻辑用于控制各种中断请求,并根据优先级的高低对中断请求进行排队,逐个交给CPU处理。

      指令控制逻辑要完成取指令、分析指令和执行指令的操作,其过程分为取指令、指令译码、按指令操作码执行、形成下一条指令等步骤。

      指令寄存器(IR)

      当CPU执行一条指令时,先把它从内存储器取到缓冲寄存器中,在送入IR暂存,指令译码器根据IR的内容产生各种微操作指令,控制其他的组成部件工作,完成所需的功能。

      程序计数器(PC)

      PC具有寄存信息和计数两种功能,又称为指令计数器。程序的执行分为两种情况,一是顺序执行,而是转移执行。当程序开始执行前,将程序的起始地址送入PC,该地址在程序加载到内容是确定,因此PC的内容即是程序第一条指令的地址。执行指令时CPU自动修改PC的内容,以便使其保持的总是将要执行的下一条指令的地址。

      地址寄存器(AR)

      AR保存当前CPU所访问的内存单元的地址。由于内存和CPU存在着操作速度上的差异,所以需要使用AR保持地址信息,知道内存的读写操作完成为止。

      指令译码器(ID)

      指令分为操作码和地址码两部分,为了能执行任何给定的指令,必须对操作码进行分析,以便识别所完成的操作。ID就是对指令中的操作码字段进行分析解释,识别该指令规定的操作,向操作控制器发出具体的控制信号,控制各部件工作,完成所需的功能。

      寄存器组

      寄存器组可分为专用寄存器和通用寄存器。运算器和控制器中的寄存器是专用寄存器,起作用是固定的。通用寄存器用途广泛并可由程序员规定其用途,其数目因处理器不同有所差异。

      指令执行过程

      

      MOV指令

      取指阶段:

      程序计数器PC装入第一条指令的地址101,PC的内容被放到指令地址总线上,对指令进行译码并启动读命令。从101号地址读出MOV指令,通过指令总线IBus装入指令寄存器IR,程序计数器PC内容加1,变成102,为下一条指令做好准备。指令寄存器IR中的操作码被译码,CPU识别出是MOV指令,至此取指阶段完成。

      执行阶段:

      操作控制器OC送出控制信号到通用寄存器,选择R1(10)为源寄存器,RO(00)为目标寄存器。OC送出控制信号到ALU,指定ALU做传送操作,打开ALU输出三态门,将ALU输出(10)送的数据总线DBus上,任何时刻DBus上只能有一个数据。将DBus上的数据打入数据缓冲寄存器DR,将DR中的数据打入目标寄存器RO,RO的内容由00变为10至此MOV指令执行完毕。

      LAD指令

      取指阶段:

      LAD指令的取指阶段和MOV指令完全相同。

      执行阶段:

      OC发出控制命令,打开IR输出三态门,将指令中的直接地址码6放到数据总线DBus上,装入地址寄存器AR,将数存6号单元中的数100读出到DBus上,装入缓冲寄存器DR。将DR中的数100装入通用寄存器R1,原来R1中的值10被覆盖,至此LAD指令执行完毕。

      ADD指令

      取指阶段:

      ADD指令的取指阶段和其他指令相同。

      执行阶段:

      操作控制器OC送出控制信号到通用寄存器,选择R1(100)为源寄存器,R2(20)为目标寄存器。ALU做R1和R2的加法运算,打开ALU输出三态门,将运算结果120放到数据总线DBus上,然后打入缓冲寄存器DR。ALU产生的进位信号保存在状态字寄存器PSW中,将DR中数值120装入R2中,R2原来的数20被覆盖。到此ADD指令执行结束。

      STO指令

      取指阶段:

      STO指令的取指阶段和其他指令相同。

      执行阶段:

      操作控制器OC送出控制信号到通用寄存器,选择R3(30)作为数据存储器的地址。打开通用寄存器输出三态门,将地址30放到DBus上并装入地址寄存器AR,并进行地址译码。操作控制器OC送出控制信号到通用寄存器,选择R2(120)作为数存的写入数据放到DBus上。将数值120写入数存30单元,原先的数据40被冲掉。至此STO指令执行结束。

      JMP指令

      取指阶段:

      JMP指令的取指周期和其他指令相同。

      执行阶段:

      OC发出控制命令,打开IR输出三态门,将IR中的地址码101发送到DBus上,将DBus上的地址码101打入到程序计数器PC中,PC中原先的地址106被更换。于是下一条指令不是从106单元取出,而是转移到101单元取出。至此JMP指令执行周期结束。

      以上内容是对于CPU功能、组成以及执行指令的一些总结和整理,有不足之处,希望大家批评指正。

    展开全文
  • Java 代码 编译和执行过程

    万次阅读 2016-07-24 14:42:43
    java 编译 执行过程
  • gradle 插件以及执行过程解析

    千次阅读 2021-01-30 16:22:46
    gradle 插件以及执行过程解析 Android Studio ,项目都是使用 Gradle 来构建的,那么我们通常使用的 Gradle 插件是如何执行的呢? Gradle 的执行步骤 简单说 gradle 是一种构建工具,用来控制代码的编译、构建...
  • 说说Python程序的执行过程

    千次阅读 2015-05-07 23:14:42
    说说Python程序的执行过程 1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在。如果是解释型语言,...
  • windows可执行程序的执行过程

    千次阅读 2017-05-26 18:14:03
    前面: 最近研究一个VC界面库DuiLib,细读它的源码时遇到些问题,比如 它的界面是如何绘制上去的,底层操作是如何实现的,就是CreateWindow和 ShowWindow又是如何实现的, 也不得而知, 因此我想有必要...
  • C语言编译执行过程详解

    千次阅读 2016-01-21 17:43:38
    认识C编译执行过程,是C学习的开端。 简单说C语言从编码编译到执行要经历一下过程:   C源代码 编译---->形成目标代码,目标代码是目标机器上运行的代码。 连接---->将目标代码与C函数库相连接,并将源程序...
  • 1、什么是聚焦最重要目标 将你最好的精力集中到一两个最重要的目标上来,而非平均地放到十几个目标上去——这一两个目标应该是能够使你得到革命性结果的事情。 聚焦,并非要缩减日常事务的规模和复杂度,日常事务...
  • MyBatis - SQL执行过程(十二)Executor

    万次阅读 2021-01-06 16:31:02
    MyBatis - SQL执行过程(十二)Executor 该系列文档是本人学习 Mybatis 的源码过程总结下来的,可能对各位读者会不太友好,阅读前需要对 MyBatis 和 Spring 有一定的了解。比较适合刚接触,会使用但是一直没去...
  • JVM原理详解-Java程序的执行过程

    万次阅读 多人点赞 2016-05-23 13:30:25
     Java虚拟机的生命周期 一个运行的Java虚拟机有着一个清晰的任务:执行Java程序。程序开始执行时他才运行,程序结束时他就停止。你同一台机器上运行三个程序,就会有三个运行的Java虚拟机。 Java虚拟机总是...
  • c语言程序的执行过程

    千次阅读 2018-02-03 13:56:07
    编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序。 C源程序...
  • Android运行时ART执行类方法的过程分析

    万次阅读 多人点赞 2014-11-10 01:00:24
    前面一篇文章,我们分析了ART运行时加载类以及查找其方法的过程。一旦找到了目标类方法,我们就可以获得它的DEX字节码或者本地...本文,我们就将通过分析ART运行时执行类方法的过程来理解ART运行时的运行原理。
  • 使用OnTime安排执行过程

    千次阅读 2010-06-16 20:08:00
    使用OnTime安排执行过程 <br />你可能需要设计Excel工作簿定期并自动地运行一个过程。例如,你可能想每隔几分钟从数据源更新数据。使用VBA,你能执行Excel应用程序的OnTime方法指令Excel给定的时间去...
  • 前言:作为开发人员,我认为我与项目经理、需求之间总是存在很多误会,其中造成误会最深的地方就是项目经理与需求沟通的时候觉得自己知道了就行了。...今天就谈谈工作沟通和执行力的重要性。 1.沟通到底有多
  • makefile定义作用及其执行过程

    千次阅读 2016-04-22 17:21:07
    Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为...
  • 更多《PHP7内核剖析》系列文章:https://github.com/pangudashu/php7-internal3.3 Zend引擎执行过程Zend引擎主要包含两个核心部分:编译、执行:前面分析了Zend的编译过程以及PHP用户函数的实现,接下来分析下Zend...
  • Chromium为网页的标签创建了Plugin之后,Plugin就负责渲染标签的内容。Chromium为Plugin提供了OpenGL接口,使得Plugin可网页上渲染3D内容。当然,我们也可通过WebGL...本文接下来就详细分析Plugin执行3D渲染的过程
  • Android应用程序UI硬件加速渲染的动画执行过程分析

    万次阅读 多人点赞 2015-06-23 01:00:40
    通常我们说一个系统不如另一个系统流畅,说的就是前者动画显示不如后者流畅,因此动画显示流畅程度是衡量一个系统流畅性的关键指标...本文就分析Render Thread显示动画的过程,以便了解它是如何提高动画显示流畅性的。
  • 88-zend_execute的具体执行过程

    千次阅读 2016-04-28 22:01:04
    88-zend_execute的具体执行过程解释器引擎最终执行op的函数是zend_execute,实际上zend_execute是一个函数指针,引擎初始化的时候zend_execute默认指向了execute,这个execute定义{...op_array *op_array TSRM
  • Semi-Space(SS)GC和Generational Semi-Space(GSS)GC是ART运行时引进的两个Compacting GC。它们的共同特点是都具有一个From Space和一个To Space。...本文就将SS GC和GSS GC的执行过程分析进行详细分析。
  • Presto查询执行过程 Presto包含三类角色,coordinator,discovery,worker。coordinator负责query的解析和调度。discovery负责集群的心跳和角色管理。worker负责执行计算。 presto-cli提交的查询,实际上是一个...
  • Oracle实现定时执行存储过程

    千次阅读 2016-04-27 16:29:54
    一:简单测试job的创建过程案例: 1,先创建一张JOB_TEST表,字段为a 日期格式 SQL> create table JOB_TEST(a date);...2,创建一个存储过程 bb 作用是往pig表插入数据 SQL> create or replace procedure JOB_P
  • 共享池数据库可以说是相当重要动力资源,关系着数据库的性能瓶颈。 什么是共享池呢?  共享池是内存结构SGA(系统全局区)的一部分,包含了:库缓冲区、数据字典缓冲区、服务器结果缓冲区、预留池,也是着...
  • Python解释执行原理及过程

    万次阅读 2014-03-25 15:59:17
    谈到了Python语句的两种执行方式,实际上,这两种运行方式本质 上是相同的,它们都是由解释器来解释执行我们提供的Python语句。 这里所说的解释执行是相对于编译执行而言的。我们知道,使用诸如 C或C++之类的编译...
  • Hive SQL执行过程源码解析(Hive3.1)

    千次阅读 2019-11-01 17:01:41
    看上面整理的代码注释,可以了解整个执行过程核心的一些步骤: 首先SQL进入Driver.compile使用ANTLR进行编译,生成AST; 然后使用BaseSemanticAnalyzer.analyze调用语法文件获得初步的执行计划Plan; 之后调用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,117,455
精华内容 446,982
关键字:

在执行过程中最重要的是