前端工程师吐后端工程师(第四讲)——Nodejs的Hello World与Go的Hello World

        任何一门语言的入门都是Hello World都已经成为一门语言入门的定律。我们为什么要用Nodejs来做对比呢,因为对于前端工程师来讲,看到JavaScript语句那就叫一个亲切,给大家拉进一下学习的关系。下面让我们先创建一个叫HelloWorld.js的文件,里面只有一行代码。console.log("Hello World"),然后在HelloWorld.js同级目录下,执行node HelloWorld.js我们会看到下面这张图。


        接下来我们要写一个Go的Hello World了。首先创建一个HelloWorld.go的文件。文件代码如下:

package main

import "fmt"

func main(){

    fmt.Println("Hello World");

}

我们执行一下go run HelloWorld.go。就能看到下图


        两个Hello World程序均已经运行起来了,让我们看看两个Hellow World都分别做了什么。

        先说Nodejs,他其实在执行的时候做了很多事儿,我们就调几个主要的说。

(1)获取默认执行执行环境。

(2)创建进程,并且把进程默认title设置为blah;

(3)载入 V8 、OpenSSL 

(4)创建Nodejs独立的上下文空间。

(5)初始化一大堆默认环境对象扔进 (2)中创建的进程。

(6)执行HelloWorld.js获取系统依赖对象,调用系统console实例做页面输出。

这里并不是完整的流程,底层还涉及到libuv中心的调度,这里就不做详细讲解了,感兴趣的同学去看看Nodejs启动时,执行的node.cc。

        接下来我们在说说Go语言都做了什么,这次我们不用打开Go的源文件那么复杂了,我们只需要执行


前端工程师吐后端工程师(第四讲)——Nodejs的Hello World与Go的Hello World_第1张图片

        当然如果想了解更底层的内存管理等,可以使用GBD来进行分析观察,我们这里只介绍一下能跟Nodejs含义有对比性的流程。像MOVQ和LEAQ这种加载内存指令到寄存器就不做分析了,意义不大。

(1)获取默认执行执行环境。 我使用的电脑是MAC ,初始化对应指令集(达尔文原始码操作系统),用GBD分析的话可以看到如下信息。代码如下:

(gdb) info symbol 0x1051fd0

_rt0_amd64_darwin in section .text

(2)使用JMP在指定标号地址创建执行进程。代码如下:

TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8

JMP _rt0_amd64(SB)


前端工程师吐后端工程师(第四讲)——Nodejs的Hello World与Go的Hello World_第2张图片

(3)初始化命令行、OS层对接初始化、调度器初始化; 

(4)创建goroutine队列,该 goroutine 绑定 runtime.main,放在 P 的本地队列,等待调度(这是第一个有大的不同点,goroutine也是Go的一大特色,理论上他比线程开销更小大概1:500的开销比。而且无论创建、销毁、切换都比线程要优秀)

(5)执行主进程中的goroutine队列。

(6)递归寻找 main.go 所依赖的包,循环依赖会异常退出。(这些依赖关系会形成一棵倒着生长的树,树根在最上面,就是 main.go 文件,最下面是没有任何其他依赖的包。编译器会从最左的节点所代表的包开始挨个编译,完成之后,再去编译上一层的包。第二点差异,nodejs的查找方式是文件查找,且不会形成树形结构。)

(7)编译.go文件、link编译之后的exe文件。(第三点差异nodejs没有显式link的过程,此exe不是windows下的 exe,泛指所有可执行文件)。

(8)界面输出Hello World。


        本章从两种语言启动的阶段做了比较,两者有不同是一定的,主要是让大家从根本的运行机制上有一个了解,虽所我们要介绍的是应用层面的东西,不用研究很深,但是还跟大家强度虽然咱们是类比学习,但是他们真的完全是两个东西。


参考资料:https://blog.csdn.net/u010853261/article/details/84901386

陈辰(CC老师)    [email protected]

你可能感兴趣的:(前端工程师吐后端工程师(第四讲)——Nodejs的Hello World与Go的Hello World)