【Golang 面试 - 进阶题】每日 3 题(六)
✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/UWz06
📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
16. 什么是 sync.Once?
sync.Once 是 Go 语言中的一个同步原语,用于实现只执行一次的操作。它可以保证在多个 Goroutine 中只执行一次指定的操作,即使这个操作被多次调用。
sync.Once 的使用非常简单,只需要创建一个 sync.Once 类型的变量,然后使用 Do() 方法来指定要执行的操作。Do() 方法会保证指定的操作只会被执行一次,无论它被调用多少次。下面是一个简单的例子:
var once sync.Once
func setup() {fmt.Println("Performing setup...")
}
func main() {// 在第一次调用时执行 setup 函数once.Do(setup)// 在第二次调用时不执行任何操作once.Do(func() { fmt.Println("This shouldn't be printed.") })
}
在这个例子中,我们首先定义了一个 sync.Once 类型的变量 once。然后,我们使用 once.Do() 方法来指定要执行的操作。在第一次调用时,Do() 方法会执行 setup() 函数,输出 "Performing setup..."。在第二次调用时,Do() 方法不会执行任何操作,因为 setup() 函数已经被执行过了。
需要注意的是,
Do()方法是阻塞的,也就是说,在第一次调用还没有完成之前,后续的调用会被阻塞。这个特性可以用来保证只有一个 Goroutine 执行指定的操作,而其他 Goroutine 等待它完成之后再继续执行。此外,Do()方法只会执行一次指定的操作,即使在多个 Goroutine 中调用它。这个特性可以用来避免重复初始化等问题。
17. 什么操作叫做原子操作?
在并发编程中,原子操作是一种不可中断的操作,要么全部完成,要么全部不完成。这意味着在多线程环境下,原子操作可以保证数据的一致性和可靠性,防止多个线程同时对同一数据进行操作而导致的竞争条件和数据不一致。
在 Go 语言中,sync/atomic 包提供了一些原子操作函数,用于在多线程环境中执行原子操作。这些原子操作函数可以确保对共享变量的访问是原子的,即不会被其他线程打断。
例如,atomic.AddInt64() 函数可以对一个 int64 类型的变量进行原子加法操作。以下是一个简单的示例:
package main
import ("fmt""sync/atomic"
)
func main() {var count int64// 对 count 变量进行 100 次原子加法操作for i := 0; i < 100; i++ {atomic.AddInt64(&count, 1)}fmt.Println("count:", count)
}
在这个例子中,我们首先定义了一个 int64 类型的变量 count,并使用 atomic.AddInt64() 函数对它进行 100 次原子加法操作。AddInt64() 函数的第一个参数是一个指向 int64 类型变量的指针,它告诉函数要对哪个变量进行原子操作。第二个参数是要添加的值。在这个例子中,我们每次添加的值都是 1。最后,我们输出 count 变量的值,应该是 100。
需要注意的是,原子操作函数仅保证对共享变量的访问是原子的,但并不能保证对多个变量之间的操作是原子的。如果需要对多个变量进行原子操作,可以使用互斥锁或其他同步机制来保证线程安全。
18. Go 原子操作有哪些?
Go atomic 包是最轻量级的锁(也称无锁结构),可以在不形成临界区和创建互斥量的情况下完成并发安全的值替换操作,不过这个包只支持 int32/int64/uint32/uint64/uintptr 这几种数据类型的一些基础操作(增减、交换、载入、存储等)。
概念:
原子操作仅会由一个独立的 CPU 指令代表和完成。原子操作是无锁的,常常直接通过 CPU 指令直接实现。 事实上,其它同步技术的实现常常依赖于原子操作。
使用场景:
当我们想要对某个变量并发安全的修改,除了使用官方提供的 mutex,还可以使用 sync/atomic 包的原子操作,它能够保证对变量的读取或修改期间不被其他的协程所影响。
atomic 包提供的原子操作能够确保任一时刻只有一个 goroutine 对变量进行操作,善用 atomic 能够避免程序中出现大量的锁操作。
常见操作:
-
增减 Add
-
载入 Load
-
比较并交换 CompareAndSwap
-
交换 Swap
-
存储 Store
atomic 操作的对象是一个地址,你需要把可寻址的变量的地址作为参数传递给方法,而不是把变量的值传递给方法。下面将分别介绍这些操作:
增减操作
此类操作的前缀为 Add:
func AddInt32(addr *int32, delta int32) (new int32)
func AddInt64(addr *int64, delta int64) (new int64)
func AddUint32(addr *uint32, delta uint32) (new uint32)
func AddUint64(addr *uint64, delta uint64) (new uint64)
func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)
需要注意的是,第一个参数必须是指针类型的值,通过指针变量可以获取被操作数在内存中的地址,从而施加特殊的 CPU 指令,确保同一时间只有一个 goroutine 能够进行操作。
使用举例:
func add(addr *int64, delta int64) {atomic.AddInt64(addr, delta) //加操作fmt.Println("add opts: ", *addr)
}
载入操作
此类操作的前缀为 Load:
func LoadInt32(addr *int32) (val int32)
func LoadInt64(addr *int64) (val int64)
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
func LoadUint32(addr *uint32) (val uint32)
func LoadUint64(addr *uint64) (val uint64)
func LoadUintptr(addr *uintptr) (val uintptr)
// 特殊类型: Value类型,常用于配置变更
func (v *Value) Load() (x interface{}) {}
载入操作能够保证原子的读变量的值,当读取的时候,任何其他 CPU 操作都无法对该变量进行读写,其实现机制受到底层硬件的支持。
使用示例:
func load(addr *int64) {fmt.Println("load opts: ", atomic.LoadInt64(&opts))
}
比较并交换
此类操作的前缀为 CompareAndSwap,该操作简称 CAS,可以用来实现乐观锁:
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)
该操作在进行交换前首先确保变量的值未被更改,即仍然保持参数 old 所记录的值,满足此前提下才进行交换操作。CAS 的做法类似操作数据库时常见的乐观锁机制。
需要注意的是,当有大量的 goroutine 对变量进行读写操作时,可能导致 CAS 操作无法成功,这时可以利用 for 循环多次尝试。
使用示例:
func compareAndSwap(addr *int64, oldValue int64, newValue int64) {if atomic.CompareAndSwapInt64(addr, oldValue, newValue) {fmt.Println("cas opts: ", *addr)return}
}
交换
此类操作的前缀为 Swap:
func SwapInt32(addr *int32, new int32) (old int32)
func SwapInt64(addr *int64, new int64) (old int64)
func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
func SwapUint32(addr *uint32, new uint32) (old uint32)
func SwapUint64(addr *uint64, new uint64) (old uint64)
func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)
相对于 CAS,明显此类操作更为暴力直接,并不管变量的旧值是否被改变,直接赋予新值然后返回被替换的值。
func swap(addr *int64, newValue int64) {atomic.SwapInt64(addr, newValue)fmt.Println("swap opts: ", *addr)
}
存储
此类操作的前缀为 Store:
func StoreInt32(addr *int32, val int32)
func StoreInt64(addr *int64, val int64)
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
func StoreUint32(addr *uint32, val uint32)
func StoreUint64(addr *uint64, val uint64)
func StoreUintptr(addr *uintptr, val uintptr)
// 特殊类型: Value类型,常用于配置变更
func (v *Value) Store(x interface{})
此类操作确保了写变量的原子性,避免其他操作读到了修改变量过程中的脏数据。
func store(addr *int64, newValue int64) {atomic.StoreInt64(addr, newValue)fmt.Println("store opts: ", *addr)
}
相关文章:
【Golang 面试 - 进阶题】每日 3 题(六)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
Unity横板动作游戏 -项目准备
项目准备 这是一篇 Unity 2022 最新稳定版本的教程同步笔记,本文将会讲解一些开始学习必须的条件。 安装环境 首先是安装 UnityHub,然后在 UnityHub 中安装 Unity 的版本(2022)。 只需要安装 开发者工具 和文档即可,导出到其他平台的工具等…...
基于Gunicorn + Flask + Docker的高并发部署策略
标题:基于Gunicorn Flask Docker的高并发部署策略 引言 随着互联网用户数量的增长,网站和应用程序需要能够处理越来越多的并发请求。Gunicorn 是一个 Python WSGI HTTP 服务器,Flask 是一个轻量级的 Web 应用框架,Docker 是一…...
jdk版本管理利器-sdkman
1.什么是sdkman? sdkman是一个轻量级、支持多平台的开源开发工具管理器,可以通过它安装任意主流发行版本(例如OpenJDK、Kona、GraalVM等等)的任意版本的JDK。通过下面的命令可以轻易安装sdkman: 2.安装 curl -s "https://…...
Kafka知识总结(事务+数据存储+请求模型+常见场景)
文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 事务 事务Producer保证消息写入分区的原子性,即这批消…...
C#中重写tospring方法
在C#中,重写ToString方法允许你自定义对象的字符串表示形式。当你想要打印对象或者在调试时查看对象的状态时,重写ToString方法非常有用。 默认情况下,ToString方法返回对象的类型名称。通过重写这个方法,你可以返回一个更有意义…...
【机器学习基础】机器学习的数学基础
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科,通过算法和模型让计算机从数据中学习,进行模型训练和优化,做出预测、分类和决策支持。Python成为机器学习的首选语言,…...
fastapi之零
FastAPI 详细介绍 FastAPI 是一个现代、快速(高性能)的 web 框架,用于构建 API。它基于标准的 Python 类型提示,使用 Starlette 作为 web 框架,Pydantic 进行数据验证和解析。以下是对 FastAPI 的详细介绍,…...
SpringBoot整合PowerJob 实现远程任务
PowerJob介绍 PowerJob 是全新一代分布式任务调度和计算框架,提供了可视化界面,可通过单机、远程等形式调用任务并提供了运行监控和日志查看的功能模块,是当前比较流行的分布式定时任务框架之一; PowerJob 官网文档地址 环境搭建…...
【扒模块】DFF
图 医学图像分割任务 代码 import torch import torch.nn as nnfrom timm.models.layers import DropPath # 论文:D-Net:具有动态特征融合的动态大核,用于体积医学图像分割(3D图像任务) # https://arxiv.org/abs/2403…...
frameworks 之Socket
frameworks 之Socket Socket服务端1.创建Socket。2.绑定socket3.监听socket4.等待客户端连接5.读取或者写入给客户端 客户端1.创建Socket。2.连接服务端Socket3.读取或者写入给客户端4.关闭socket 演示代码 Epoll创建Epoll添加或删除Epoll等待消息返回Epoll演示代码 SocketPair…...
WEB前端开发中如何实现大文件上传?
大文件上传是个非常普遍的场景,在面试中也会经常被问到,大文件上传的实现思路和流程。在日常开发中,无论是云存储、视频分享平台还是企业级应用,大文件上传都是用户与服务器之间交互的重要环节。随着现代网络应用的日益复杂化&…...
ts给vue中props设置指定类型
interface IBaseObject {[key: string | number]: any; }export default defineComponent({name:xx,props:{data:{type:Object as PropType<IBaseObject>,default:()>({}),required:true},}, })...
模拟实现c++中的list模版
☺☺☺☺☺☺☺☺☺☺ 点击 进入杀马特的主页☺☺☺☺☺☺☺☺☺☺ 目录 一list简述: 二库内常用接口函数使用: 1reverse(): 2.s…...
从信息论的角度看微博推荐算法
引言 在数字时代,推荐系统已成为社交媒体和其他在线服务平台的核心组成部分。它们通过分析用户行为和偏好,为用户提供个性化的内容,从而提高用户满意度和平台的参与度。推荐系统不仅能够增强用户体验,还能显著提升广告投放的效率…...
CISC(复杂指令集)与RISC(精简指令集)的区别
RISC(Reduced Instruction Set Computer)和CISC(complex instruction set computer)是当前CPU的两种架构。 它们的区别在于不同的CPU设计理念和方法。 早期的CPU全部是CISC架构,它的设计目的是要用最少的机器语言指令来完成所需的计算任务。比如对于乘法运算&#x…...
自定义数据库连接的艺术:Laravel中配置多数据库连接详解
自定义数据库连接的艺术:Laravel中配置多数据库连接详解 在现代Web应用开发中,经常需要连接到多个数据库。Laravel,作为PHP界最受欢迎的框架之一,提供了强大的数据库抽象层,支持多种数据库系统,并且允许开…...
力扣高频SQL 50题(基础版)第八题
文章目录 力扣高频SQL 50题(基础版)第八题1581. 进店却未进行过交易的顾客题目说明思路分析实现过程准备数据:实现方式:结果截图:总结: 力扣高频SQL 50题(基础版)第八题 1581. 进店…...
【C++20】从0开始自制协程库
文章目录 参考 很多人对协程的理解就是在用户态线程把CPU对线程的调度复制了一遍,减少了线程的数量,也就是说在一个线程内完成对协程的调度,不需要线程切换导致上下文切换的开销。但是线程切换是CPU行为,就算你的程序只有一个线程…...
Docker 深度解析:从入门到精通
引言 在当今的软件开发领域,容器化技术已经成为一种趋势。Docker 作为容器化技术的代表,以其轻量级、可移植性和易用性,被广泛应用于各种场景。本文将从 Docker 的基本概念入手,详细介绍 Docker 的安装、基本操作、网络配置、数据…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
