1. 什么是 GoroutineGoroutine 是 Go 语言中的一种轻量级线程实现。相比传统线程,Goroutine的开销更小,因此可以在同一进程内运行成千上万个 Goroutine,使得 Go 能够更高效地处理并发任务。
在 Go 中,Goroutine 以独立的协程形式执行,通过 go 关键字启动。所有的 Goroutine 在同一地址空间中运行,可以直接共享数据,但需要小心并发冲突。
2. Goroutine 的基本用法要启动一个 Goroutine,我们只需在函数调用前添加 go 关键字:
12345678910111213141516package mainimport ( "fmt" "time")func sayHello() { fmt.Println("Hello from Goroutine")}func main() { go sayHello() fmt.Println("Hello from main") t ...
1. 类型断言类型断言允许我们从接口类型中提取出具体的类型。这对于处理接口时非常有用,因为接口类型在 Go 中是动态的。类型断言有两种形式:
1.1 基本类型断言基本的类型断言语法是:
1value, ok := x.(T)
x 是接口类型,T 是目标类型。
value 是断言的结果,如果类型断言成功,value 就是类型 T 的值。
ok 是布尔值,表示类型断言是否成功。
如果类型断言失败,ok 会返回 false,并且 value 会是该类型的零值。如果没有 ok,则类型断言失败时会触发 panic。
123456789101112131415package mainimport "fmt"func main() { var x interface{} = "Hello, Go!" // 类型断言 str, ok := x.(string) if ok { fmt.Println("类型断言成功:", str) } else ...
1. 接口的定义与使用Go 中的接口是通过一组方法签名来定义的,接口不需要显式地声明方法的实现。也就是说,如果某个类型实现了接口所要求的所有方法,那么这个类型就自动实现了该接口,无需显示声明。
一个简单的接口定义示例:
1234567891011121314151617181920212223// 定义接口package mainimport "fmt"type Speaker interface { Speak() string}// 定义结构体type Person struct { Name string}// 实现接口方法func (p Person) Speak() string { return "Hello, my name is " + p.Name}func main() { var speaker Speaker = Person{Name: "杨幂"} fmt.Println(speak ...
1. 环境准备
一个域名(已托管在 Cloudflare)
开通 Cloudflare 账号并获取 API Token
2. 安装 acme.sh首先,我们需要安装 acme.sh。这个工具使用非常简单,可以帮我们直接申请 Let’s Encrypt 或 ZeroSSL 等的免费证书。
运行以下命令来安装 acme.sh:1curl https://get.acme.sh | sh
这条命令会将 acme.sh 安装到你的主目录下的 .acme.sh 目录中,并且自动配置好环境变量。
检查安装是否成功:1~/.acme.sh/acme.sh --version
如果显示版本号,那说明安装成功!
3. 配置 Cloudflare API Token在 Cloudflare 获取 API Token:
登录到你的 Cloudflare 账号。
进入 API Tokens 页面,创建一个新的 Token。
为 Token 设置以下权限:
Zone:DNS - Edit
选择需要的域名,或者可以直接选择所有域。
生成后,复制这个 Token,我们接下来会用到它。
设置 Clou ...
1. 包的作用域在 Go 中,包(Package)为代码的组织和访问控制提供了基础。理解包的作用域和导出规则有助于提高代码的可读性、复用性和模块化设计。在 Go 中,包是作用域的最小单位,所有在包内定义的变量、常量、类型和函数都只在当前包中可见。
局部作用域:包内的每个 .go 文件的顶级定义可以在同一包的其他文件中访问。
全局作用域:包的导出规则决定哪些标识符能被其他包访问。
包的设计让我们在控制访问的同时,也能轻松地将通用功能分离到不同的包中进行管理。
2. 导出规则Go 中判断标识符是否导出的依据很简单:如果标识符以大写字母开头,那么它就是导出的,可以被其他包访问;否则则是包内私有的。
例如:
12345// 导出func PublicFunc() {}// 不导出func privateFunc() {}
这种简单的规则让代码更易读,无需额外注解或关键字。
3. 包内变量和函数的访问控制包内的变量和函数主要通过首字母大小写来控制访问:
小写字母开头的函数、变量和常量仅在包内可见。
大写字母开头的标识符可以导出并供其他包访问。
...
1. 模块和 go.mod 文件Go 1.11 引入了 go mod 来管理项目依赖,从此 Go 的依赖管理不再依赖 GOPATH。Go 的模块是管理依赖的基本单位,每个模块都有一个 go.mod 文件,定义了模块的路径、依赖的库和版本信息。
go.mod 文件包含如下内容:
module:模块名,一般是仓库的 URL。
go:Go 语言的版本。
require:项目依赖的模块及其版本。
2. 初始化模块在新项目中使用 go mod init 命令来初始化模块。比如,假设你正在开发一个叫 myapp 的项目,可以执行以下命令:
1go mod init example.com/myapp
这样会生成一个 go.mod 文件,内容大概如下:
123module example.com/myappgo 1.18
此时模块已创建,下一步可以添加代码和依赖。
3. 添加和更新依赖在代码中使用新的第三方库时,go mod 会自动将依赖添加到 go.mod。例如,在代码中导入 github.com/gorilla/mux后,运行 go run 或 go build 时,go.mod 会 ...
1. Go 包的基本概念Go 的设计强调包的使用。简单来说,每个 .go 文件的开头第一行一般是 package 声明,比如:
1package main
在 main 包中的代码可以直接编译成可执行程序。
其他包则是库代码,供其他包导入使用。
这样设计让代码模块化,也方便管理和复用。
2. 创建自定义包要创建一个包,首先在你的项目文件夹下创建一个新的文件夹,这个文件夹的名字就是你的包名。在该文件夹下创建 .go文件,并在文件中声明 package 包名。
假设我们想创建一个处理字符串的工具包 stringutils,步骤如下:
创建文件夹 stringutils。
在文件夹中创建文件 utils.go。
在文件开头声明包名:
123456789101112// 文件:stringutils/utils.gopackage stringutils// 定义一个函数func Reverse(s string) string { // 简单实现一个反转字符串的函数 r := []rune(s) for i, j := 0, len(r)-1; i & ...
1. fmt 包fmt 包用于格式化输入和输出,提供了便捷的函数来打印数据和格式化字符串。
常用函数
fmt.Print、fmt.Println:直接输出到控制台。
fmt.Printf:支持格式化输出。
fmt.Sprintf:格式化并返回字符串。
示例12345name := "Alice"age := 30fmt.Printf("Name: %s, Age: %d\n", name, age)str := fmt.Sprintf("Hello, %s!", name)fmt.Println(str)
2. math 包math 包提供了数学运算的基础函数,包括基本的数学计算、三角函数、对数函数等。
常用函数
基本运算:math.Abs、math.Max、math.Min。
指数运算:math.Pow、math.Sqrt。
三角函数:math.Sin、math.Cos、math.Tan。
示例123a, b := 3.0, 4.0hypotenuse := math.Sqrt(math.Pow(a, 2) + ma ...
一、堆内存大小调整堆内存是 JVM 中用来存放对象的主要区域,合理配置堆内存可以减少垃圾回收(GC)的频率和停顿时间。
-Xms(或 -XX:InitialHeapSize):初始堆大小。通常设置为 Xmx 的相同值,避免运行时动态扩展堆内存,减少性能开销。
-Xmx(或 -XX:MaxHeapSize):最大堆大小,避免内存过度使用,导致系统资源不足。
调优建议:根据应用的内存需求和服务器的内存容量,合理设置堆大小。堆过小会导致频繁 GC,堆过大可能导致其他进程性能下降。
二、垃圾回收器(GC)选择JVM 提供了多种垃圾回收器,可用于不同的性能需求和场景:
-XX:+UseParallelGC:并行 GC,适用于吞吐量优先的应用,适合多核服务器。
-XX:+UseG1GC:G1 GC,适用于低延迟需求的应用,尤其是大堆内存场景,减少 GC 停顿。
-XX:+UseConcMarkSweepGC:CMS GC,减少老年代的停顿时间,适用于低延迟场景。
调优建议:在吞吐量优先的场景下,优先选择并行 GC;对延迟敏感或大内存的场景推荐 G1 GC 和 CMS GC。
三、年轻代和老 ...
指针是 Go 语言中非常重要的概念之一。它允许我们直接操作变量的内存地址,从而实现更高效的内存管理。Go语言中的指针可以进行引用、解引用,还可以用作函数参数来实现指针传递。
1. 指针的引用在 Go 语言中,可以使用 & 操作符来获取变量的地址,从而创建指向该变量的指针。
123var x int = 10var ptr *int = &x // 使用 & 获取 x 的地址,并赋给 ptrfmt.Println(ptr) // 输出 x 的地址
在上述代码中,ptr 是一个指针,指向变量 x 的内存地址。*int 表示 ptr 是一个指向整数类型的指针。
2. 指针的解引用指针保存的是地址,要获取指针指向的值,可以使用 * 操作符。这种操作被称为“解引用”。
123fmt.Println(*ptr) // 输出指针 ptr 所指向的值,即变量 x 的值*ptr = 20 // 通过指针修改 x 的值fmt.Println(x) // 输出 20
通过解引用操作,可以直接修改指针所指向变量的值,从而实现对原始数据的直接操作。 ...