精华内容
下载资源
问答
  • 在听到 nodejs 相关特性时,经常会对 异步I/O、非阻塞I/O有所耳闻,听起来好像是差不多意思,但其实是两码事,下面我们就以原理角度来剖析一下对 nodejs 来说,这两种技术底层是如何实现?什么是I/O?首先,...

    在听到 nodejs 相关的特性时,经常会对 异步I/O非阻塞I/O有所耳闻,听起来好像是差不多的意思,但其实是两码事,下面我们就以原理的角度来剖析一下对 nodejs 来说,这两种技术底层是如何实现的?

    什么是I/O?

    首先,我想有必要把 I/O 的概念解释一下。I/O 即Input/Output, 输入和输出的意思。在浏览器端,只有一种 I/O,那就是利用 Ajax 发送网络请求,然后读取返回的内容,这属于网络I/O。回到 nodejs 中,其实这种的 I/O 的场景就更加广泛了,主要分为两种:

    • 文件 I/O。比如用 fs 模块对文件进行读写操作。
    • 网络 I/O。比如 http 模块发起网络请求。

    阻塞和非阻塞I/O

    阻塞非阻塞 I/O 其实是针对操作系统内核而言的,而不是 nodejs 本身。阻塞 I/O 的特点就是一定要等到操作系统完成所有操作后才表示调用结束,而非阻塞 I/O 是调用后立马返回,不用等操作系统内核完成操作。

    对前者而言,在操作系统进行 I/O 的操作的过程中,我们的应用程序其实是一直处于等待状态的,什么都做不了。那如果换成非阻塞I/O,调用返回后我们的 nodejs 应用程序可以完成其他的事情,而操作系统同时也在进行 I/O。这样就把等待的时间充分利用了起来,提高了执行效率,但是同时又会产生一个问题,nodejs 应用程序怎么知道操作系统已经完成了 I/O 操作呢?

    为了让 nodejs 知道操作系统已经做完 I/O 操作,需要重复地去操作系统那里判断一下是否完成,这种重复判断的方式就是轮询。对于轮询而言,有以下这么几种方案:

    1. 一直轮询检查I/O状态,直到 I/O 完成。这是最原始的方式,也是性能最低的,会让 CPU 一直耗用在等待上面。其实跟阻塞 I/O 的效果是一样的。

    2. 遍历文件描述符(即 文件I/O 时操作系统和 nodejs 之间的文件凭证)的方式来确定 I/O 是否完成,I/O完成则文件描述符的状态改变。但 CPU 轮询消耗还是很大。

    3. epoll模式。即在进入轮询的时候如果I/O未完成CPU就休眠,完成之后唤醒CPU。

    总之,CPU要么重复检查I/O,要么重复检查文件描述符,要么休眠,都得不到很好的利用,我们希望的是:

    nodejs 应用程序发起 I/O 调用后可以直接去执行别的逻辑,操作系统默默地做完 I/O 之后给 nodejs 发一个完成信号,nodejs 执行回调操作。

    这是理想的情况,也是异步 I/O 的效果,那如何实现这样的效果呢?

    异步 I/O 的本质

    Linux 原生存在这样的一种方式,即(AIO), 但两个致命的缺陷:

    1. 只有 Linux 下存在,在其他系统中没有异步 I/O 支持。
    2. 无法利用系统缓存。

    nodejs中的异步 I/O 方案

    是不是没有办法了呢?在单线程的情况下确实是这样,但是如果把思路放开一点,利用多线程来考虑这个问题,就变得轻松多了。我们可以让一个进程进行计算操作,另外一些进行 I/O 调用,I/O 完成后把信号传给计算的线程,进而执行回调,这不就好了吗?没错,异步 I/O 就是使用这样的线程池来实现的

    只不过在不同的系统下面表现会有所差异,在 Linux 下可以直接使用线程池来完成,在Window系统下则采用 IOCP 这个系统API(其内部还是用线程池完成的)。

    有了操作系统的支持,那 nodejs 如何来对接这些操作系统从而实现异步 I/O 呢?

    以文件为 I/O 我们以一段代码为例:

    let fs = require('fs');fs.readFile('/test.txt', function (err, data) {    console.log(data); });

    执行流程

    执行代码的过程中大概发生了这些事情:

    1. 首先,fs.readFile调用Node的核心模块fs.js ;
    2. 接下来,Node的核心模块调用内建模块node_file.cc,创建对应的文件I/O观察者对象(这个对象后面有大用!) ;
    3. 最后,根据不同平台(Linux或者window),内建模块通过libuv中间层进行系统调用
    c7abefe45824d30f9bd836927211753c.png

    libuv调用过程拆解

    重点来了!libuv 中是如何来进行进行系统调用的呢?也就是 uv_fs_open() 中做了些什么?

    1. 创建请求对象

    以Windows系统为例来说,在这个函数的调用过程中,我们创建了一个文件I/O的请求对象,并往里面注入了回调函数。

    req_wrap->object_->Set(oncomplete_sym, callback);

    req_wrap 便是这个请求对象,req_wrap 中 object_ 的 oncomplete_sym 属性对应的值便是我们 nodejs 应用程序代码中传入的回调函数。

    2. 推入线程池,调用返回

    在这个对象包装完成后,QueueUserWorkItem() 方法将这个对象推进线程池中等待执行。

    好,至此现在js的调用就直接返回了,我们的 js 应用程序代码可以继续往下执行,当然,当前的 I/O 操作同时也在线程池中将被执行,这不就完成了异步么:)

    等等,别高兴太早,回调都还没执行呢!接下来便是执行回调通知的环节。

    3. 回调通知

    事实上现在线程池中的 I/O 无论是阻塞还是非阻塞都已经无所谓了,因为异步的目的已经达成。重要的是 I/O 完成后会发生什么。

    在介绍后续的故事之前,给大家介绍两个重要的方法: GetQueuedCompletionStatusPostQueuedCompletionStatus

    1. 还记得之前讲过的 eventLoop 吗?在每一个Tick当中会调用GetQueuedCompletionStatus检查线程池中是否有执行完的请求,如果有则表示时机已经成熟,可以执行回调了。

    2. PostQueuedCompletionStatus方法则是向 IOCP 提交状态,告诉它当前I/O完成了。

    名字比较长,先介绍是为了让大家混个脸熟,至少后面出来不会感到太突兀:)

    我们言归正传,把后面的过程串联起来。

    当对应线程中的 I/O 完成后,会将获得的结果存储起来,保存到相应的请求对象中,然后调用PostQueuedCompletionStatus()向 IOCP 提交执行完成的状态,并且将线程还给操作系统。一旦 EventLoop 的轮询操作中,调用GetQueuedCompletionStatus检测到了完成的状态,就会把请求对象塞给I/O观察者(之前埋下伏笔,如今终于闪亮登场)。

    I/O 观察者现在的行为就是取出请求对象存储结果,同时也取出它的oncomplete_sym属性,即回调函数(不懂这个属性的回看第1步的操作)。将前者作为函数参数传入后者,并执行后者。这里,回调函数就成功执行啦!

    总结 :

    1. 阻塞非阻塞 I/O 其实是针对操作系统内核而言的。阻塞 I/O 的特点就是一定要等到操作系统完成所有操作后才表示调用结束,而非阻塞 I/O 是调用后立马返回,不用等操作系统内核完成操作。
    2. nodejs中的异步 I/O 采用多线程的方式,由 EventLoopI/O 观察者请求对象线程池四大要素相互配合,共同实现。
    展开全文
  • Python的核心数据类型: 1,Python中当执行下面代码时会引发什么类型的错误: apple = mango NameError: name ‘mango’ is not defined 赋值为...2,如何解释下面的执行结果? print(1.2 - 1.0 == 0.2) False (浮...

    Python的核心数据类型:
    1,Python中当执行下面代码时会引发什么类型的错误:
    apple = mango

    NameError: name ‘mango’ is not defined 赋值为字符串时,字符串要加引号;赋值为一个不带引号的字串时,说明引用了一个变量,但mango并非已定义的变量.

    2,如何解释下面的执行结果?
    print(1.2 - 1.0 == 0.2)
    False

    (浮点数无法精确表示 )
    任何编程语言的浮点数做算术运算后,其精度都是无法保证的,有的是0.199999之类的数,或者其四舍五入的数

    3,Python不支持的数据类型有:char
    char是character的简写,就是字符的意思,在Java里特指单个字符,例如字母a。在python里面没有该数据类型。

    4,关于Python中的复数,下列说法错误的是:
    A.Python的复数由实数部分和虚数部分构成,可以用a + bj表示
    B.实部和虚部都是浮点数
    C.虚部必须后缀j,且必须是小写
    D.Python的复数可以用complex(a,b)表示
    (虚部可以用大写J作为后缀)

    5,True在Python语言中是:
    A.一个关键词
    B.一个布尔类型值
    C.和1相同
    D.和0相同
    (True为布尔类型,其值和1相同,True == 1的结果为True;True == 0,结果为False;同时也是个关键词)

    表达式及算术运算符:
    1,下列表达式的值为True的是
    A.‘ab’ > “ba”
    B.3>2>2
    C.‘abc’ > 'abb’
    D.‘abc’ > ‘xyz’
    (字符串比大小,首先比第一个字母,有结果就不比较后边的了
    选项A:字母a的asc比字母b要小,所以false
    选项B:2>2是false
    选项D:字母a的asc比字母x要小,所以false)

    2,下列代码运行结果是?
    a = ‘a’
    print (a > ‘a’ or ‘c’)
    A.a
    B.c
    C.True
    D.False
    【正确答案】B
    【答案解析】对python而言
    其一, 在不加括号时候, and优先级大于or
    其二, x or y 的值只可能是x或y. x为真就是x, x为假就是y
    第三, x and y 的值只可能是x或y. x为真就是y, x为假就是x
    此题里a > “a"为假,所以返回"c”

    内置函数:
    1,Python3.X环境下,下列代码的输出结果是()
    x = ‘a’
    print(chr(ord(x) + 1))
    A.a
    B.b
    C.c
    D.d
    【正确答案】B
    【答案解析】ord()函数,把一个字符串表示的字符转换为字符相对应的整数,适用于UNICODE字符;
    chr()函数用一个范围在range(256)内的(0~255)整数作参数,返回一个对应的字符。

    (单选题) s = ‘hello’ 求s[6::-1]的值为()
    A.‘olleh’
    B.‘hello’
    C.‘e’
    D.以上都不对
    【正确答案】A(起始点越界不存在,但是python会忽略这个错误,从最后一个开始,)
    【答案解析】Python中符合序列的有序序列都支持切片(slice),例如列表,字符串,元组。

    已知li=[“A”,“B”,“C”,“D”],那么li[0:4:2]的值为()
    A.[“A”,“B”,“C”]
    B.[“C”,“D”]
    C.[“B”,“C”]
    D.[“A”,“C”]
    【正确答案】D
    【答案解析】 li[start : end : step]
    start是切片起点索引,end是切片终点索引,但切片结果不包括终点索引的值。step是步长默认是1
    从li[0]到li[3],设定步长为2

    (单选题)dict = {‘Name’: ‘Runoob’, ‘Age’: 7, ‘Name’: ‘小菜鸟’}
    print ("dict[‘Name’]: ", dict[‘Name’])
    以下哪个输出结果是正确的()
    A.dict[‘Name’]: 小菜鸟
    B.dict[‘Name’]: Runoob
    C.dict[‘Name’]: 小菜鸟,Runoob
    D.以上都不对
    【正确答案】A
    【答案解析】创建时如果同一个键被赋值两次,后一个值会被记住

    展开全文
  • 先来看下表1,表名为test: 表1  执行如下SQL语句: 1 ... 你应该很容易知道运行的结果,没错,就是下表2: ...下面说说如何来思考上面SQL语句执行情况: 1.FROM test:该句执行后,应该结果和...

    先来看下表1,表名为test:

     

    表1

      执行如下SQL语句:

    1

    2

    SELECT name FROM test

    GROUP BY name

    你应该很容易知道运行的结果,没错,就是下表2:

    表2

    可是为了能够更好的理解“group by”多个列“”聚合函数“的应用,我建议在思考的过程中,由表1到表2的过程中,增加一个虚构的中间表:虚拟表3。下面说说如何来思考上面SQL语句执行情况:

    1.FROM test:该句执行后,应该结果和表1一样,就是原来的表。

    2.FROM test Group BY name:该句执行后,我们想象生成了虚拟表3,如下所图所示,生成过程是这样的:group by name,那么找name那一列,具有相同name值的行,合并成一行,如对于name值为aa的,那么<1 aa 2>与<2 aa 3>两行合并成1行,所有的id值和number值写到一个单元格里面。

    3.接下来就要针对虚拟表3执行Select语句了:

    (1)如果执行select *的话,那么返回的结果应该是虚拟表3,可是id和number中有的单元格里面的内容是多个值的,而关系数据库就是基于关系的,单元格中是不允许有多个值的,所以你看,执行select * 语句就报错了。

    (2)我们再看name列,每个单元格只有一个数据,所以我们select name的话,就没有问题了。为什么name列每个单元格只有一个值呢,因为我们就是用name列来group by的。

    (3)那么对于id和number里面的单元格有多个数据的情况怎么办呢?答案就是用聚合函数,聚合函数就用来输入多个数据,输出一个数据的。如cout(id),sum(number),而每个聚合函数的输入就是每一个多数据的单元格。

    (4)例如我们执行select name,sum(number) from test group by name,那么sum就对虚拟表3的number列的每个单元格进行sum操作,例如对name为aa的那一行的number列执行sum操作,即2+3,返回5,最后执行结果如下:

    (5)group by 多个字段该怎么理解呢:如group by name,number,我们可以把name和number 看成一个整体字段,以他们整体来进行分组的。如下图

    (6)接下来就可以配合select和聚合函数进行操作了。如执行select name,sum(id) from test group by name,number,结果如下图:

    铁子们,如果觉得文章对你有所帮助,可以点关注,点赞

    也可以关注下公众号:扫码 或 wx搜索:“聊5毛钱的java ,欢迎一起学习交流,关注公众号可领取博主的Java学习视频+资料,保证都是干货

    3Q~

    展开全文
  • 转载链接:https://juejin.im/post/5c7f3cb25188251b883cada2作者:walkinger来源:掘金int==Integer为什么返回true先看现象吧执行下面的代码及输出结果:int 通常大家对此的解释是,==对于基本类型来说比较的是值,...
    转载
    链接:https://juejin.im/post/5c7f3cb25188251b883cada2
    作者:walkinger
    来源:掘金

    int==Integer为什么返回true

    先看现象吧
    执行下面的代码及输出结果:

    int 


    通常大家对此的解释是,==对于基本类型来说比较的是值,对于引用类型来说比较的是引用,即指向的对象的内存地址。这样解释没错,b==c结果为false毋庸置疑,因为两个都是引用类型。但是为什么a==b(a==c)一个是基本类型一个是引用类型,比较的时候还是值比较呢?


    这个时候我们不妨把.java源文件编译后的.class文件使用反编译工具反编译成源码,看看虚拟机内部是如何处理a==b的。

    .class文件使用jd-gui反编译后的:

    int 


    看到这想必大家都明白了吧,其实基本类型a和引用类型b比较时,引用类型b调用自身的intValue()方法获取Integer实际表示的int类型的值,即a == b.intValue()还是两个int类型的变量进行值比较。符合上述:==对于基本类型来说比较的是值,对于引用类型来说比较的是引用,即指向的对象的内存地址。


    基本类型及引用类型在内存中的存储方式


    说到这,还要解释下为什么两个引用类型的值一样而引用不一样以及基本变量为什么是值比较。


    其实基本变量int a在内存里只有一份,保存在栈(保存基本类型的变量数据及引用类型的引用)中,Integer b和Integer c中的int值都指向栈中同一个int,不会重新在栈中创建相同的int值。


    而对于Integer b和Integer c,其实例是保存在堆(保存所有new出来的对象)中,虽然表示的int值相同,但是在堆中有两份,每次new都会在堆中开辟一片空间保存new的内容,故Integer b和Integer c分别在两片不同的内存空间存储,所以指向的内存地址不同。

    abdf81060918b975137aeb87aef1bca9.png

    而对于Integer b = 1;其反编译后为Integer b = Integer.valueOf(1); 而valueOf()方法内部是调用了new。

    JDK中Integer.valueOf()源码:

    public 

    总结

    了解原理是弄清问题的关键,像这样的问题以后还多着呢。不懂的时候可以敲敲代码,然后反编译,看看虚拟机是怎么处理的,看看原理翻翻源码,问题也就迎刃而解了。

    展开全文
  • 原:...int==Integer为什么返回true 先看现象吧 执行下面的代码及输出结果: int a = 1; Integer b = 1; Integer c = new Integer(1); System.out.println(a==b);//true System.out.printl...
  • explain模拟优化器,我可以通过explain来查看mysql是如何处理sql语句,分析查询语句或者表结构性能瓶颈。 语法:explain + sql语句 ...下面我们来解释一下执行结果每个属性 1.id id 执行顺序 :...
  • 文章目录前言结论如何解释两种结果的不同:补充 前言 Go语言中延迟函数defer充当着 try…catch 的重任,使用起来也非常简便,然而在实际应用中,很多gopher并没有真正搞明白defer、return和返回值之间的执行顺序,...
  • mysql执行计划

    2018-08-21 11:08:55
    下面是一个简单EXPLAIN的结果:       解释执行计划中EXPLAIN列   ID列   是一位数字,表示执行SELECT语句顺序。 id值相同执行顺序从上到下。 id值不同时id值大执行。 SELECT_TYPE   这...
  • 这一篇主要说明解释基本工作过程和JSC核心组件实现。 作为一个语言,就像人在平时交流时一样,当接收到信息后,包含两个过程:先理解再行动。...下面就来看看JSC是如何来理解、执行JavaScript脚
  • 解释抽象语法树

    千次阅读 2014-06-04 14:28:13
    这一小节先讨论如何解释结果,下面一小节再讨论编译的内容,最后,再讨论何时应该用解释,何时应该用编译的问题。 下面的例子是一个很小解释器,解释抽象语法树的主要工作由函数interpret 完成,它遍历树,并同时...
  • 怎么看mysql执行计划

    2021-03-23 20:17:23
    这时候,我们就需要查看sql的执行计划,以此来分析sql执行缓慢的问题所在。 如何查看mysql执行计划 方法一:使用explain(推荐) explain select * from t_user; 方法二:使用Navicat解释执行 执行计划...
  • 从前端上传一个文件,然后服务器利用可执行文件来把上传文件内容稍作修改输出到另一个结果文件,然后后端php再把生成的结果文件内容输出到前端网页、 下面来说一下具体流程。 前端html表单经过提交action到index...
  • 寻找注入点(如:登录界面、留言板等)b) 用户自己构造SQL语句(如:' or 1=1#,后面会讲解)c) 将sql语句发送给数据库管理系统(DBMS)d) DBMS接收请求,并将该请求解释成机器代码指令,执行必要存取操作e) DBMS接受...
  • 下面三段代码会执行结果什么不同2.为什么第一段会栈溢出3.为什么第二段会正常4.为什么第三段会卡住页面5.为什么使⽤栈结构来管理函数调⽤?6.栈如何管理函数调⽤?7.既然有了栈,为什么还要堆?8.什么是惰性解析9....
  • shell 脚本如何调试

    2012-12-08 10:54:03
    shell脚本由于是解释执行语言,不像java那样可以进行调试 如果想调试shell脚本,可以在执行shell时加上-x参数,例如 sh -x start.sh ...例如下面的结果: + '[' panorama = eve ']' + more /home/panorama
  • 下面我们来分析这段代码,上图左边是实际代码过程,右边为执行的结果。 **Python中一切皆对象。**绝对不是一句空话,在Python的解释器里,不仅有自己定义是对象,使我们传统意义上认为一切东西都是对象,对于...
  • 下面的例子会在控制台中打印出一些信息(具体打印出什么?可以猜猜😀),然后返回<code>hello world。 <pre><code> javascript let koa = require('koa') let app = koa() app....
  • For example:为str输入一个变量,print打印显示结果为2那么如何对字符串str实现一些修改呢,下面我们来学习一些字符串常用命令。1.upper首先是upper这个命令,它功能是可以把字符串变成大写。For example:...
  • 在正式开始之前,我们先看一段代码: 下面我们来分析这段代码,上图左边是实际代码过程,右边为执行的结果。 Python中一切皆对象。绝对不是一句空话,在Python的解释器里,不仅有自己定义是对象,使我们传统...
  • 使用Excel创建线性回归模型

    千次阅读 2020-07-03 12:40:25
    下面是一个教程,介绍如何在Excel中构建线性回归模型以及如何解释结果 介绍 Excel真能构建预测模型? 这通常是我提起这个话题时第一反应。当我演示如何利用Excel灵活性为我们数据科学和分析项目构建预测...
  • 运行 Pause 命令时,将显示下面的消息: Press any key to continue . . . Sample: @echo off :begin copy a:*.* d:back echo Please put a new disk into driver A pause goto begin 在这个例子中,驱动...
  • 下面是我一些具体一些关于doors资料 <pre name="code" class="java">目前有两款比较成熟需求管理工具: Telelogic Doors 和 RequisitePro 总结如下: 优点: 1. Doors支持多项目(文件)之间...
  • eval()函数用来执行由字符串所构成的语句 ...eval()函数的返回值就是string的执行返回结果,如何理解string的执行结果下面给几个例子解释一下:1 + 2上面这段表达式的执行结果毋庸置疑会是3, 所以如果你调用e
  • 当我使用expandtabs时,如何计算字符串长度,我感到困惑。我认为expandtabs会用适当数量空格替换标签(默认...Python展开制表符长度计算下面是一个详细脚本输出和注释,解释了我认为应该是上面执行的命令的结果...
  • 是对量子力学一种解释,可以帮助理解叠加和干涉。 路径积分: 电路原理图: 如何读取路径积分图: 随着时间在左右比特上执行门操作,时间从左向右流动。 箭头从一种状态过渡到另一种状态,并遍历箭头可提供...
  • 问题源自知乎—浪子神剑老师前端面试每日 3+1,我仅在此为大家提供解题方案以及思路,在此感谢浪子神剑老师。... [js] 根据下面代码:说出执行结果,并解释为何是会是这样结果? var str = 'abc'; ...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 223
精华内容 89
关键字:

如何解释下面的执行结果