为什么golang在并发环境下更有优势
Go语言(Golang)在并发环境下的优势主要源自其设计哲学和内置的并发机制,这些机制在语言层面提供了高效、简洁且安全的并发编程工具。以下是其核心优势的详细分析:
1. Goroutine:轻量级并发单元
- 轻量级 :Golang的
goroutine
是用户级线程(协程),启动时仅需 2KB 的栈内存 (动态扩展),而传统线程通常需要 1MB+。这使得程序可以轻松创建成千上万个并发任务,而不会因资源耗尽导致崩溃。 - 低启动开销 :创建和销毁
goroutine
的代价极低(纳秒级),无需依赖操作系统的线程管理,适合高频短任务的场景(如处理HTTP请求)。 - 自动调度 :Go运行时(runtime)通过调度器自动管理
goroutine
的生命周期,开发者无需手动管理线程池。
2. GMP 调度模型:高效的并发调度
Go的调度器采用 M:N 模型 (多对多调度),将大量goroutine
映射到少量操作系统线程(OS Thread)上,核心组件包括:
- G(Goroutine):并发任务单元。
- M(Machine):操作系统线程,由内核调度。
- P(Processor) :逻辑处理器,管理本地
goroutine
队列(每个P绑定一个M)。
优势:
- 工作窃取(Work Stealing) :空闲的P会从其他P的队列中"窃取"
goroutine
,实现负载均衡。 - 非阻塞系统调用 :当
goroutine
触发系统调用(如I/O)时,调度器会将M与P解绑,避免线程阻塞,并立即分配新的M执行其他任务。 - 用户态调度:减少内核态与用户态的切换开销,上下文切换成本低于线程。
3. Channel:基于通信的并发同步
Golang通过 CSP(Communicating Sequential Processes)模型 ,提倡"通过通信共享内存,而非通过共享内存通信":
- Channel(通道) :类型安全的管道,用于
goroutine
间的数据传输和同步。- 避免显式锁(如
Mutex
),减少竞态条件和死锁风险。 - 支持阻塞式同步(如无缓冲Channel)或异步缓冲(有缓冲Channel)。
- 避免显式锁(如
- Select 多路复用 :通过
select
语句监听多个Channel,简化事件驱动编程。
示例:
go
ch := make(chan int)
go func() {
result := compute()
ch <- result // 发送结果到Channel
}()
value := <-ch // 等待并接收结果
对比传统线程模型
特性 | Golang (Goroutine) | 传统线程(如Java/Python) |
---|---|---|
内存占用 | 2KB起步,动态扩展 | 1MB+(固定栈) |
创建/销毁开销 | 纳秒级 | 微秒级 |
调度方式 | 用户态调度(高效) | 内核态调度(上下文切换慢) |
并发同步机制 | Channel(避免锁竞争) | 依赖锁(易死锁/竞态) |
开发复杂度 | 低(语法内建支持) | 高(需手动管理线程池/锁) |
总结
Go语言的并发优势源于轻量级Goroutine、高效调度器、Channel通信模型 以及标准库的全方位支持,使得开发者能够以简洁的代码构建高并发、高性能的系统,同时降低传统并发编程的复杂性。这些特性使Go成为云原生、微服务和实时系统的首选语言。
说一下什么是虚拟地址?如果没有虚拟地址,只有物理地址可以吗?
说一下线程间是如何进行通讯
go设计模式有了解过吗
参考:https://blog.csdn.net/weixin_45565886/article/details/136098371
简单工厂模式
go 语言没有构造函数,所以我们一般是通过 NewXXX 函数来初始化相关类。 NewXXX 函数返回接口时就是简单工厂模式,也就是说 Golang 的一般推荐做法就是简单工厂。
工厂方法模式
Go 中不存在继承 所以使用匿名组合来实现
示例步骤:
定义接口type operator interface
参数a
参数b
result:具体业务方法
定义type BaseFactory struct:提供方法,用于设置a、b参数
参数a
参数b
根据不同操作,定义不同工厂类(addFactory、minusFactory)
addFactory实现operator的result:a+b
minusFactory实现operator的result:a-b
addFactory、minusFactory分别提供Create方法
简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象 。
工厂方法 :多个工厂类,一个产品抽象类,利用多态创建不同的产品对象 ,避免了大量的if-else判断。
抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
go
package main
import "fmt"
/*
> - 简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
> - 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
> - 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
*/
// Operator 被封装的实际接口
type Operator interface {
SetA(int)
SetB(int)
Result() int
}
// OperatorFactory 是工厂接口
type OperatorFactory interface {
Create() Operator
}
// OperatorBase 是Operator 接口实现的基类,封装公用方法
type OperatorBase struct {
a, b int
}
func (o *OperatorBase) SetA(a int) {
o.a = a
}
func (o *OperatorBase) SetB(b int) {
o.b = b
}
// PlusOperatorFactory 加法运算的工厂类
type PlusOperatorFactory struct{}
type PlusOperator struct {
*OperatorBase
}
func (p *PlusOperator) Result() int {
return p.a + p.b
}
func (p PlusOperatorFactory) Create() Operator {
return &PlusOperator{
OperatorBase: &OperatorBase{},
}
}
// MinusOperatorFactory 减法运算的工厂类
type MinusOperatorFactory struct {
*OperatorBase
}
func (p *MinusOperatorFactory) Result() int {
return p.a - p.b
}
func (p *MinusOperatorFactory) Create() Operator {
return &MinusOperatorFactory{
OperatorBase: &OperatorBase{},
}
}
func main() {
//加法
plusFactory := PlusOperatorFactory{}
plusOperator := plusFactory.Create()
plusOperator.SetA(10)
plusOperator.SetB(20)
result := plusOperator.Result()
fmt.Println("plusOperator=", result)
//减法
minusFactory := MinusOperatorFactory{}
minusOperator := minusFactory.Create()
minusOperator.SetA(10)
minusOperator.SetB(5)
result = minusOperator.Result()
fmt.Println("minusOperator=", result)
}
创建者模式
将build一个物品拆分为几个部分
go
package main
import "fmt"
// Goods 构建的对象
type Goods struct {
Name string
Price float64
Count int
}
// GoodsBuilder 构建器
type GoodsBuilder interface {
SetName(name string) GoodsBuilder
SetPrice(price float64) GoodsBuilder
SetCount(count int) GoodsBuilder
Build() *Goods
}
// ConcreteBuilder 具体构建器
type ConcreteBuilder struct {
goods *Goods
}
func (g ConcreteBuilder) Build() *Goods {
return g.goods
}
func (g ConcreteBuilder) SetName(name string) GoodsBuilder {
g.goods.Name = name
return g
}
func (g ConcreteBuilder) SetPrice(price float64) GoodsBuilder {
g.goods.Price = price
return g
}
func (g ConcreteBuilder) SetCount(count int) GoodsBuilder {
g.goods.Count = count
return g
}
func NewGoodsBuilder() GoodsBuilder {
return &ConcreteBuilder{
goods: &Goods{},
}
}
func main() {
builder := NewGoodsBuilder()
goods := builder.SetName("apple").SetCount(2).SetPrice(65.0).Build()
fmt.Println(goods)
}
单例模式
懒汉式:用到时才实例化(GetInstance),通过once.Do保证只加载一次
饿汉式:一开始就实例化(init)
go
package main
import (
"fmt"
"sync"
)
// 懒汉式:用到才加载【饿汉式:直接放在init方法里,程序一启动就创建好】
var (
instance *Singleton
once = sync.Once{}
)
type Singleton struct {
}
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
func main() {
one := GetInstance()
two := GetInstance()
//one=0x100f54088
//two=0x100f54088
fmt.Printf("one=%p\n", one)
fmt.Printf("two=%p\n", two)
}
...
https讲一下,如何进行加密的

HTTPS 通过 SSL/TLS 协议 对通信数据进行加密,确保数据在传输过程中不被窃取或篡改。其核心加密机制结合了对称加密 和非对称加密 ,并通过数字证书验证身份。以下是具体流程:
一、SSL/TLS 握手(建立安全连接)
-
客户端发起请求
浏览器访问 HTTPS 网站时,发送支持的加密算法列表(如 RSA、ECDHE)和 TLS 版本。
-
服务器响应
服务器选择加密算法,并返回数字证书(包含公钥、域名、签发机构等信息)。
-
证书验证
- 浏览器检查证书是否由受信任的证书颁发机构(CA)签发。
- 验证证书是否过期、域名是否匹配,防止中间人攻击。
二、密钥交换(核心加密步骤)
-
非对称加密传递对称密钥
- 浏览器生成一个随机数(Pre-master Secret ),用证书中的公钥加密后发送给服务器。
- 服务器用私钥解密获取 Pre-master Secret。
-
生成会话密钥
双方根据 Pre-master Secret 和握手阶段的随机数,生成相同的对称密钥(如 AES 密钥),后续通信使用此密钥加密数据。
为什么混合使用两种加密?
- 非对称加密(如 RSA)安全性高,但计算慢,适合交换密钥。
- 对称加密(如 AES)速度快,适合加密大量数据。
三、加密数据传输
- 握手完成后,双方使用对称密钥加密所有通信内容。
- 即使数据被截获,攻击者无法解密(没有密钥)。
四、关键技术支持
-
数字证书
- 由 CA 颁发,证明服务器身份,防止伪造。
- 包含公钥、域名、有效期等信息,并由 CA 私钥签名。
-
加密算法
- 非对称加密:RSA、ECDHE(密钥交换)。
- 对称加密:AES、ChaCha20(数据加密)。
- 散列算法:SHA-256(验证数据完整性)。
-
完整性校验
使用 HMAC 或 AEAD 模式,确保数据未被篡改。
五、总结流程
客户端 → 服务器:发起请求,支持哪些加密算法?
服务器 → 客户端:返回证书和选定的算法。
客户端验证证书 → 生成随机密钥用公钥加密 → 发送给服务器。
服务器用私钥解密 → 双方生成对称密钥。
后续通信全部使用对称密钥加密。
通过以上步骤,HTTPS 实现了:
- 机密性(对称加密数据)
- 身份认证(数字证书验证)
- 完整性(散列算法防篡改)
这使得 HTTPS 成为保护隐私(如密码、支付信息)的核心技术。