5.28 后端面经

为什么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 握手(建立安全连接)

  1. 客户端发起请求

    浏览器访问 HTTPS 网站时,发送支持的加密算法列表(如 RSA、ECDHE)和 TLS 版本。

  2. 服务器响应

    服务器选择加密算法,并返回数字证书(包含公钥、域名、签发机构等信息)。

  3. 证书验证

    • 浏览器检查证书是否由受信任的证书颁发机构(CA)签发。
    • 验证证书是否过期、域名是否匹配,防止中间人攻击。

二、密钥交换(核心加密步骤)

  1. 非对称加密传递对称密钥

    • 浏览器生成一个随机数(Pre-master Secret ),用证书中的公钥加密后发送给服务器。
    • 服务器用私钥解密获取 Pre-master Secret。
  2. 生成会话密钥

    双方根据 Pre-master Secret 和握手阶段的随机数,生成相同的对称密钥(如 AES 密钥),后续通信使用此密钥加密数据。

为什么混合使用两种加密?

  • 非对称加密(如 RSA)安全性高,但计算慢,适合交换密钥。
  • 对称加密(如 AES)速度快,适合加密大量数据。

三、加密数据传输

  • 握手完成后,双方使用对称密钥加密所有通信内容。
  • 即使数据被截获,攻击者无法解密(没有密钥)。

四、关键技术支持

  1. 数字证书

    • 由 CA 颁发,证明服务器身份,防止伪造。
    • 包含公钥、域名、有效期等信息,并由 CA 私钥签名。
  2. 加密算法

    • 非对称加密:RSA、ECDHE(密钥交换)。
    • 对称加密:AES、ChaCha20(数据加密)。
    • 散列算法:SHA-256(验证数据完整性)。
  3. 完整性校验

    使用 HMAC 或 AEAD 模式,确保数据未被篡改。


五、总结流程

复制代码
客户端 → 服务器:发起请求,支持哪些加密算法?
服务器 → 客户端:返回证书和选定的算法。
客户端验证证书 → 生成随机密钥用公钥加密 → 发送给服务器。
服务器用私钥解密 → 双方生成对称密钥。
后续通信全部使用对称密钥加密。

通过以上步骤,HTTPS 实现了:

  • 机密性(对称加密数据)
  • 身份认证(数字证书验证)
  • 完整性(散列算法防篡改)

这使得 HTTPS 成为保护隐私(如密码、支付信息)的核心技术。

相关推荐
啊阿狸不会拉杆3 分钟前
[特殊字符]《计算机组成原理》第 8 章 - CPU 的结构和功能
java·开发语言·计算机组成原理
疯狂的沙粒13 分钟前
React与Vue的内置指令对比
开发语言·前端·javascript·vue.js
黄雪超40 分钟前
JVM——SubstrateVM:AOT编译框架
java·开发语言·jvm
[email protected]41 分钟前
Asp.Net Core 通过JWT版本号实现JWT无法提前撤回的问题
后端·中间件·asp.net·.netcore
编码小笨猪41 分钟前
[ Qt ] | Qlabel使用
开发语言·c++·qt
吃个糖糖44 分钟前
Halcon联合QT ROI绘制
开发语言·qt
还有几根头发呀44 分钟前
double怎么在c/c++中输出保留输出最小精度为一位
c语言·开发语言·c++
ademen1 小时前
spring4第4课-ioc控制反转-详解如何注入参数
java·后端·spring
Hello-Mr.Wang1 小时前
使用electron创建应用程序的基础步骤
后端·electron
天天代码码天天1 小时前
PP-OCRv5 C++封装DLL C#调用源码分享
开发语言·c++·c#·ocr