最新golang语言面试题总结(三)
1、go中拼接字符串有几种方式
1、"+"
最常用的方法就是,使用"+"将两个字符串进行连接,与Python类似,不过Go语言中的字符串是不可变的类型,因此用"+"进行连接会产生一个新的字符串,这样对效率会有所影响。
a := "字符串" b := "拼接" c := a+b fmt.Print(c) //c = "打印字符串"
2、使用sprintf函数
第二种方法,就是使用sprintf函数,虽然不会像直接使用+那样产生临时的字符串,但效率也不高。
a := "字符串" b := "拼接" c := fmt.Sprintf("%s%s", a, b) //c = "打印字符串"
3、使用Join函数
第三种方法就是,使用Join函数,这里需要先引入strings包才能调用Join函数,此函数会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,如果没有的话效率也不高。
//需要先导入strings包 a := "字符串" b := "拼接" //定义一个字符串数组包含上述的字符串 var str []string = []string{a, b} //调用Join函数 c := strings.Join(str, "") fmt.Print(c)
4、调用buffer.WriteString函数
第四种方法就是,调用buffer.WriteString函数,此方法的性能要远远大于上面的方法。
//需要先导入bytes包 a := "字符串" b := "拼接" //定义Buffer类型 var bt bytes.Buffer 向bt中写入字符串 bt.WriteString(a) bt.WriteString(b) //获得拼接后的字符串 c := bt.String()
5、用buffer.Builder
第五种方法是用buffer.Builder,此方法和上面的差不多,不过官方建议使用这个,且使用方法和上面基本一样。
//需要先导入Strings包 a := "字符串" b := "拼接" var build strings.Builder build.WriteString(a) build.WriteString(b) c := build.String()
2、go中"_"的作用
1、import中的下滑线
此时“_”的作用是:当导入一个包的时候,不需要把所有的包都导进来,只需要导入使用该包下的文件里所有的init()的函数。
package mainimport _ "hello/imp"func main() {//imp.Print() //编译报错,说:undefined: imp
2、下划线在代码中
作用是:下划线在代码中是忽略这个变量也可以理解为占位符,那个位置上本应该赋某个值,但是我们不需要这个值,所以就把该值给下划线,意思是丢掉不要,这样编译器可以更好的优化,任何类型的单个值都可以丢给下划线。
如果方法返回两个值,只想要其中的一个结果,那另一个就用_占位
package mainimport "fmt"v1, v2, _ := function(...)
3、占位符
"_"是特殊标识符,用来忽略结果
3、使用go实现99乘法表
for i := 1; i < 10; i++ {for j := 1; j <= i; j++ {fmt.Printf("%d*%d=%d ", j, i, i*j)}fmt.Println("")}结果:
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
4、linux命令,查看端口占用,cpu负载,内存占用,如何发送信号给一个进程、修改文件权限
Linux 查看端口占用情况:lsof -i:端口号netstat -tunlp | grep 端口号cpu负载:uptime内存占用:top如何发送信号给一个进程:1. kill() 函数2. alarm() 函数修改文件权限:chmod命令用于修改文件权限
5、Redis redo log, binlog 与 undo log
redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。
6、使用三个协程,每秒钟打印cat dog fish
使用三个协程,每秒钟打印cat dog fish 注意:1、顺序不能变化(协程1打印cat,协程2打印dog,协程3打印fish)2、无限循环即可/* 使用三个协程,每秒钟打印cat dog fish 注意:顺序不能变化(协程1打印cat,协程2打印dog,协程3打印fish) 无限循环即可 */ func main() {wg := sync.WaitGroup{}wg.Add(3)chcat := make(chan int)chdog := make(chan int)chfish := make(chan int)go printCat(&wg, chcat, chfish)go printDog(&wg, chdog, chcat)go printfash(&wg, chfish, chdog)wg.Wait() } func printDog(wg *sync.WaitGroup, dog chan int, cat chan int) {defer wg.Done()for {<-catfmt.Println("dog")time.Sleep(time.Second)dog <- 1} } func printCat(wg *sync.WaitGroup, cat chan int, fish chan int) {defer wg.Done()for {cat <- 1fmt.Println("cat")time.Sleep(time.Second)<-fish} } func printfash(wg *sync.WaitGroup, fish chan int, dog chan int) {defer wg.Done()for {<-dogfmt.Println("fish")time.Sleep(time.Second)fish <- 1} }
7、Go出现panic的场景
go中发生panic的场景: - 数组/切片越界 - 空指针调用。比如访问一个 nil 结构体指针的成员 - 过早关闭 HTTP 响应体 - 除以 0 - 向已经关闭的 channel 发送消息 - 重复关闭 channel - 关闭未初始化的 channel - 未初始化 map。注意访问 map 不存在的 key 不会 panic,而是返回 map 类型对应的零值,但是不能直接赋值 - 跨协程的 panic 处理 - sync 计数为负数。 - 类型断言不匹配。`var a interface{} = 1; fmt.Println(a.(string))` 会 panic,建议用 `s,ok := a.(string)`
8、Http是短连接还是长连接?
- 在HTTP/1.0中,默认使用的其实是短连接。也就是说,浏览器和服务器每进行一次HTTP操作,就要建立一次连接,但任务结束后就会中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话;
- 但从HTTP/1.1起,默认使用长连接,用以保持会话的连接特性。使用长连接的HTTP协议,会在响应头中加入这行代码:Connection:keep-alive;
- 在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立好的连接。但Keep-Alive也不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。我们要注意,实现长连接要客户端和服务端都支持长连接。
TCP三次握手和四次挥手过程
既然上面我们说到了三次握手和四次挥手,健哥就再扩展一下说说这两个操作的实现过程。
三次握手:先向HTTP服务器发起TCP的确认请求
- 客户端 --> SYN --> 服务器
- 服务器 --> SYN+ACK --->客户端
- 客户端 --> ACK --> 服务器
四次挥手:客户端要和服务器断开TCP连接
- 客户端 --> FIN +ACK ---> 服务器
- 服务器 --> FIN ---> 客户端
- 服务器 --> ACK --> 客户端
- 客户端 --> ACK ---> 服务器
总结
1、Http协议到底是长连接还是短连接,要看HTTP协议的版本,Http1.0中默认是短连接, 2、 Http1.1中默认是长连接;
3、 Http协议位于OSI网络模型的应用层;
4、Http协议底层在传输层上使用的是TCP协议,在网络层使用的是IP协议;
5、TCP协议具有三次握手和四次挥手的过程,传输数据安全稳定。
9、liunx协程和线程初始申请内存大小
协程初始化创立的时候为其调配的栈有2KB。而线程栈要比这个数字大的多,能够通过ulimit 命令查看,个别都在几兆,作者的机器上是10M。如果对每个用户创立一个协程去解决,100万并发用户申请只须要2G内存就够了,而如果用线程模型则须要10T。
协程和线程默认申请的内存是堆内存
10、go面试题实现一个内存缓存系统
面试题内容 1、支持设定过期时间,精度到秒 2、支持设定最大内存,当前超出时做出合适的处理 3、支持并发安全 4、按照以下接口要求实现type Cache interface {//size:1KB 100KB 1MB 2MB 1GBSetMaxMemory(size string) bool//将value写入缓存Set(key string, val interface{}, expire time.Duration) bool//根据key值获取valueGet(key string) (interface{}, bool)//删除keyDel(key string) bool//判断key是否存在Exists(key string) bool//清空所有keyFlush() bool//获取缓存中所有key的数量Keys() int64 }
1、util.go文件中代码
package cacheimport ("encoding/json""log""regexp""strconv""strings" )const (B = 1 << (iota * 10)KBMBGBTBPB )func ParseSize(size string) (int64, string) {//默认大小为100MBre, _ := regexp.Compile("[0-9]+")unit := string(re.ReplaceAll([]byte(size), []byte("")))num, _ := strconv.ParseInt(strings.Replace(size, unit, "", 1), 10, 64)unit = strings.ToUpper(unit)var byteNum int64 = 0switch unit {case "B":byteNum = numcase "KB":byteNum = num * KBcase "MB":byteNum = num * MBcase "GB":byteNum = num * GBcase "TB":byteNum = num * TBcase "PB":byteNum = num * PBdefault:num = 0byteNum = 0}if num == 0 {log.Println("ParseSize 仅支持B KB MB GB TB PB")num = 100unit = "MB"byteNum = num * MB}sizeStr := strconv.FormatInt(num, 10) + unitreturn byteNum, sizeStr } func GetValSize(val interface{}) int64 {bytes, _ := json.Marshal(val)size := int64(len(bytes))return size }
2、cache.go
package cacheimport "time"type Cache interface {//size:1KB 100KB 1MB 2MB 1GBSetMaxMemory(size string) bool//将value写入缓存Set(key string, val interface{}, expire time.Duration) bool//根据key值获取valueGet(key string) (interface{}, bool)//删除keyDel(key string) bool//判断key是否存在Exists(key string) bool//清空所有keyFlush() bool//获取缓存中所有key的数量Keys() int64 }
3、memCache.go
package cacheimport ("fmt""log""sync""time" )type memCache struct {//最大内存maxMemorySize int64//最大内存字符串表示maxMemorySizeStr string//当前已使用内存currencyMemorySize int64//缓存健值对values map[string]*memCacheValue//读写锁locker sync.RWMutex//清除过期缓存时间间隔clearExpireItemTimeInterval time.Duration } type memCacheValue struct {//value值val interface{}//过期时间expireTime time.Time//有效时长expire time.Duration//value 大小size int64 }func NewMemCache() Cache {mc := &memCache{values: make(map[string]*memCacheValue),clearExpireItemTimeInterval: time.Second * 10,}//go mc.clearExpireItem()return mc }//size:1KB 100KB 1MB 2MB 1GB func (mc *memCache) SetMaxMemory(size string) bool {mc.maxMemorySize, mc.maxMemorySizeStr = ParseSize(size)return true }//将value写入缓存 func (mc *memCache) Set(key string, val interface{}, expire time.Duration) bool {mc.locker.Lock()defer mc.locker.Unlock()v := &memCacheValue{val: val,expireTime: time.Now().Add(expire),expire: expire,size: GetValSize(val),}mc.del(key)mc.add(key, v)if mc.currencyMemorySize > mc.maxMemorySize {mc.del(key)log.Println(fmt.Sprintf("max memory size %d", mc.maxMemorySize))}return true } func (mc *memCache) Get(key string) (interface{}, bool) {mc.locker.RLock()defer mc.locker.RUnlock()mcv, ok := mc.values[key]if ok {//判断缓存是否过期if mcv.expire != 0 && mcv.expireTime.Before(time.Now()) {mc.del(key)return nil, false}return mcv.val, ok}return nil, false } func (mc *memCache) del(key string) {tmp, ok := mc.get(key)if ok && tmp != nil {mc.currencyMemorySize -= tmp.sizedelete(mc.values, key)} } func (mc *memCache) add(key string, val *memCacheValue) {mc.values[key] = valmc.currencyMemorySize += val.size }//根据key值获取value func (mc *memCache) get(key string) (*memCacheValue, bool) {val, ok := mc.values[key]return val, ok }//删除key func (mc *memCache) Del(key string) bool {mc.locker.Lock()defer mc.locker.Unlock()mc.del(key)return true }//判断key是否存在 func (mc *memCache) Exists(key string) bool {mc.locker.RLock()defer mc.locker.RUnlock()_, ok := mc.values[key]return ok }//清空所有key func (mc *memCache) Flush() bool {mc.locker.Lock()defer mc.locker.Unlock()mc.values = make(map[string]*memCacheValue, 0)mc.currencyMemorySize = 0return true }//获取缓存中所有key的数量 func (mc *memCache) Keys() int64 {mc.locker.RLock()defer mc.locker.RUnlock()return int64(len(mc.values)) } func (mc *memCache) clearExpireItem() {timeTicker := time.NewTicker(mc.clearExpireItemTimeInterval)defer timeTicker.Stop()for {select {case <-timeTicker.C:for key, item := range mc.values {if item.expire != 0 && time.Now().After(item.expireTime) {mc.locker.Lock()mc.del(key)mc.locker.Unlock()}}}} }
4、memCache_test.go
package cacheimport ("testing""time" )func TestCacheDP(t *testing.T) {testData := []struct {key stringval interface{}expire time.Duration}{{"slsd", 678, time.Second * 10},{"dds", 678, time.Second * 11},{"slsddsd", 678, time.Second * 12},{"dsd", map[string]interface{}{"a": 3, "b": false}, time.Second * 13},{"ds", "aadasdasdad", time.Second * 14},{"dsdsd", "这里是的的饿的啊得到", time.Second * 15},}c := NewMemCache()c.SetMaxMemory("10MB")for _, item := range testData {c.Set(item.key, item.val, item.expire)val, ok := c.Get(item.key)if !ok {t.Error("缓存取值失败")}if item.key != "slsddsd" && val != item.val {t.Error("缓存取值数据与预期不一致")}} }
5、main.go
package mainimport ("fmt"cache_server "test111/cache-server""time" )func main() {//fmt.Println(dns_reques.DigDomain("127.0.0.1:53", "www.baidu.com"))cache := cache_server.NewMemCache()cache.SetMaxMemory("200GB")cache.Set("aa", 1, 10*time.Second)cache.Set("bb", false, 10*time.Second)cache.Set("data", map[string]interface{}{"a": 1}, 10*time.Second)/*cache.Set("int", 1)cache.Set("bool", false)cache.Set("data", map[string]interface{}{"a": 1})*/fmt.Println(cache.Get("aa"))fmt.Println(cache.Get("bb"))fmt.Println(cache.Get("data"))cache.Del("int")cache.Flush()cache.Keys() }
最新golang语言面试题总结(三)相关推荐
- 最新golang语言面试题总结(一)
1.go中make和new区别 new: 分配内存.内存里存的值是对应类型的零值. 只有一个参数.参数是分配的内存空间所存储的变量类型,Go语言里的任何类型都可以是new的参数,比如int, 数组,结 ...
- 国二计算机c 考试内容,计算机国二C语言考试试题第三套
<计算机国二C语言考试试题第三套>由会员分享,可在线阅读,更多相关<计算机国二C语言考试试题第三套(10页珍藏版)>请在人人文库网上搜索. 1.第三套1.对下面程序描述正确的一 ...
- 2021年最新大厂php+go面试题集(三)
14.快手一面 微信公众号:码农编程进阶笔记 关注可获得更多的视频教程及面试技巧.问题或建议,请公众号留言! 1.CDn工作原理答:CDN通过广泛的网络节点分布,提供快速.稳定.安全.可编程的全球内容 ...
- c语言用户标识符不能描述常量,福建省c语言考试试题c题库选择题答案06-08(最新)...
1.12006 年年 6 月份月份2008 年年 1 月份月份C 语言等级考试语言等级考试模拟试卷模拟试卷集成集成(选择题部分选择题部分)一.选择题一.选择题1.关于.关于 C 语言数据类型的叙述,正 ...
- 国二c语言是笔试还是机,2017最新国二c语言笔试题.doc
2017最新国二c语言笔试题 2017最新国二c语言笔试题篇1 1一个C程序的执行是从( ). A) 本程序的main函数开始,到main函数结束 B) 本程序文件的第一个函数开始,到本程序文件的最后 ...
- 国二和本专业的C语言的差距,2021最新国二c语言笔试题
2021最新国二c语言笔试题 发布时间:2021-04-24 C语言是一门通用计算机编程语言,应用广泛.下面就由第一范文网小编为大家介绍一下20xx最新国二c语言笔试题的文章,欢迎阅读. 20xx最新 ...
- 2016二级c语言笔试内容,2016年计算机二级c语言笔试试题「最新」
2016年计算机二级c语言笔试试题「最新」 (25)设有如下程序段 char s[20]= "Bejing",*p; p=s; 则执行p=s;语句后,以下叙述正确的是 A)可以用* ...
- 东软 c语言笔试题,C语言笔试题及参考答案-东软集团(最新整理)
<C语言笔试题及参考答案-东软集团(最新整理)>由会员分享,可在线阅读,更多相关<C语言笔试题及参考答案-东软集团(最新整理)(7页珍藏版)>请在人人文库网上搜索. 1.C 语 ...
- 最新字节跳动面试题与岗位层级,绩效考核制度介绍
最新字节跳动面试题与岗位层级,绩效考核制度介绍 1.算法题一:无序数组的中位数 (快排思想O(N) 时间复杂度) 2.算法题二:给一数组,让你找一对满足i 3.算法题三: 给一数组,让你找一对满足i& ...
最新文章
- 关于MYSQL日期 字符串 时间戳互转
- Oracle中的UPDATE FROM解决方法
- 中科大 计算机网络11 应用层原理
- leetcode - 56. 合并区间
- form必填默认校验_Salesforce LWC学习(十六) Validity 在form中的使用浅谈
- 收获,不止SQL优化——抓住SQL的本质--第三章
- word2010生成目录的方法
- day21保护操作系统
- 鸿蒙系统装机量,王成录:华为对今年鸿蒙OS系统的装机量预估是3亿台
- android textwatcher 获取当前控件,使用TextWatcher实现EditText与TextView同步
- 基础平台系列-1-第三方服务
- “联盟鱼”-国外广告联盟lead项目最新玩法介绍
- 小青龙的Java面试笔记
- SECTION 11 安装软件程序
- 用Excel理解神经网络
- hive表信息查询:查看表结构、表操作等(转)
- 心脏支架手术后遗症 做完心脏支架手术留下后遗症
- python通过网络发送图片_python 打开网络图片
- JAVA微信登陆详解
- 客快物流大数据项目(一百一十七):网关 Spring Cloud Gateway