惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
V
V2EX
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
A
About on SuperTechFans
博客园_首页
L
LangChain Blog
量子位
雷峰网
雷峰网
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Jina AI
Jina AI
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述
Golang 编译速度为什么这么快?
2023-10-28 · via 蛮荆

2023-10-28 Golang

概述

开始接触 GO 语言的时候,笔者已经拥有 C/C++, Java 三种静态语言和 PHP, Javascript 两种动态语言的基础。正因为如此,在入门 Go 语言的过程中, 第一次编译一个几百行的 demo 文件时,着实被其编译速度惊到了,当时心中感慨: “Go 语言号称静态语言的执行速度,动态语言的编译速度,果然名不虚传”。 事实上,Google 发明 Go 语言的核心诉求就是解决其内部的大型项目代码每次构建时都需要花费很长时间的问题,抛开技术的产生历史背景, 本文着重介绍一下 Go 语言编译速度背后的主要优化方案。

极简关键字

Go 语言只有 25 个关键字,这有助于缩短编译时间。

符号表

符号表是编译器中的一种数据结构,用于存储程序中的标志符 (变量、函数、结构体/对象) 等,主要作用是提供了一个管理程序中的各种标志符的快捷方式, 以便在程序编译的不同阶段进行引用、解析、优化等工作。

Go 语言中并没有直接 (显式) 的符号表,编译器会在编译过程中创建一些内部数据结构来管理标志符和类型信息,虽然这些内部数据结构直接暴露给开发者使用的符号表, 但是可以看做是编译器的 “内部符号表”。此外,Go 语言提供了反射 (Reflection) 机制,可以在运行时获取类型、结构体字段、调用方法/堆栈 等, 也可以获取和修改对象的字段,开发者可以通过这种间接的方式获取类似符号表的信息。

依赖分析

这是 Go 语言编译速度性能提升的主要原因

消除循环依赖

循环依赖示例

Go 语言出现循环依赖会在编译时报错,在开发者解决了循环依赖问题之后,编译过程只需要递归到依赖关系树的底部即可,本质上就是一个 DFS (深度优先搜索) 过程。 此外在没有循环依赖的前提下,每个包可以独立并行编译。

依赖简化

Go 语言代码文件中只需要包含直接在代码中使用到的包名,例如当我们需要使用 Cookie 对象时, 只需要引入 cookiejar 包即可,不需要引入 http 包。

package main

import "net/http/cookiejar"

func main() {
	var c cookiejar.Jar
}

与此同时,Go 语言中引入未使用的包也会产生编译错误:

imported and not used:  ...

这个编译前置约束可以保证不相关的包对编译时间造成影响。

最后,Go 语言规定源文件中所有使用到的包必须在文件开始处 (package 语句之后) 全部列出,因此编译器无须读完整个文件内容就可以确定依赖关系。 已经编译完成的 Go 包的目标文件不仅记录了包文件的导出信息,还记录了其本身依赖的包导出信息,编译时每次导入一个目标文件即可,不需要查看其他信息。

不支持重载/重写

Go 语言不支持方法重写和方法重载,也就是说,所有的方法都可以视为静态类型的,就像 Java 里面的 static 方法。

class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!"); 
    }
}

不支持模板

Go 语言同样不支持模板方法,这可以避免模板实例化带来的性能开销。

无须虚拟机

Go 语言和 Java 一样,也是自带 GC 的语言,但是不同的地方在于,Java 是在虚拟机中编译的,因此 Java 代码在通过编译器之前必须先编译为字节码, 但是 Go 不依赖虚拟机编译代码,而是直接从源代码编译为二进制文件。

Reference