威❤ itspcool 交流学习
Go语言如何学习
Go语言语法特别简单简洁,有C的底子更好,差一些也没关系。前提是你要真心想学,才有足够的动力去学。
资源链接: https://pan.baidu.com/s/1Qq3F... 提取码: kczq
作者-\/ 307570512
前提是你要真心想学,才有足够的动力去学。初学Go语言首先弄懂基础语法和概念:基本数据类型、Struct、Array、map、Slice、指针、接口、map、内置函数,常用工具包等,还有接口和Slice的底层数据结构。这些不需要弄特别懂,能自己理解并自己描述我觉得就可以了,关键在实践和应用练习。然后学文件操作、网络编程、锁、协程、对象序列化和反序列化,以及各种数据格式的封装等,这是进阶的内容。学完上面两个阶段,就可以自己接触一些框架,然后搭建一个web服务器,来做一些测试和练习。Go各种框架都非常多了,github上star数过万的就有很多,这里列举几个:beego、iris、gin、echo、revel等。对于学习一些使用方法还是很有帮助的。在第三个阶段做的过程中,自然就接触到了数据库,io,操作系统,网络,存储优化、需要排很多雷。到这一步,已经能够模块化开发,应对正式的开发任务需求了。以上是作为从Java转过来的一枚现役goer的感悟吧,供大家讨论。下面再来说说学习资料的问题。
极客时间Go工程师零基础就业班学习 - 基础知识点
1、go的调度
2、go struct能不能比较
因为是强类型语言,所以不同类型的结构不能作比较,但是同一类型的实例值是可以比较的,实例不可以比较,因为是指针类型
3、go defer(for defer),先进后出,后进先出
4、select可以用于什么,常用语gorotine的完美退出
golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作
5、context包的用途Context通常被译作上下文,它是一个比较抽象的概念,其本质,是【上下上下】存在上下层的传递,上会把内容传递给下。在Go语言中,程序单元也就指的是Goroutine
6、client如何实现长连接
server是设置超时时间,for循环遍历的
7、主协程如何等其余协程完再操作
使用channel进行通信,context,select
8、slice,len,cap,共享,扩容
append函数,因为slice底层数据结构是,由数组、len、cap组成,所以,在使用append扩容时,会查看数组后面有没有连续内存快,有就在后面添加,没有就重新生成一个大的素组
9、map如何顺序读取
map不能顺序读取,是因为他是无序的,想要有序读取,首先的解决的问题就是,把key变为有序,所以可以把key放入切片,对切片进行排序,遍历切片,通过key取值。
10、实现set
[图片上传失败...(image-fa2b2d-1551792454360)]
实现set
11、实现消息队列(多生产者,多消费者)
1使用切片加锁可以实现
12、大文件排序
1归并排序,分而治之,拆分为小文件,在排序
13、基本排序,哪些是稳定的
14、http get跟head
1HEAD和GET本质是一样的,区别在于HEAD不含有呈现数据,而仅仅是HTTP头信息。有的人可能觉得这个方法没什么用,其实不是这样的。想象一个业务情景:欲判断某个资源是否存在,我们通常使用GET,但这里用HEAD则意义更加明确。
15、http 401,403
400 bad request,请求报文存在语法错误
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden,表示对请求资源的访问被服务器拒绝
404 not found,表示在服务器上没有找到请求的资源
16、http keep-alive
client发出的HTTP请求头需要增加Connection:keep-alive字段
Web-Server端要能识别Connection:keep-alive字段,并且在http的response里指定Connection:keep-alive字段,告诉client,我能提供keep-alive服务,并且"应允"client我暂时不会关闭socket连接
17、http能不能一次连接多次请求,不等后端返回
http本质上市使用socket连接,因此发送请求,接写入tcp缓冲,是可以多次进行的,这也是http是无状态的原因
18、tcp与udp区别,udp优点,适用场景
tcp传输的是数据流,而udp是数据包,tcp会进过三次握手,udp不需要
19、time-wait的作用
20、数据库如何建索引
21、孤儿进程,僵尸进程
22、死锁条件,如何避免
23、linux命令,查看端口占用,cpu负载,内存占用,如何发送信号给一个进程
24、git文件版本,使用顺序,merge跟rebase
25、Slice与数组区别,Slice底层结构
26、项目里的微信支付这块,在支付完微信通知这里,收到两次微信相同的支付通知,怎么防止重复消费(类似接口的幂等性),说了借助Redis或者数据库的事务
27、项目里的消息推送怎么做的(业务有关)
28、Go的反射包怎么找到对应的方法(这里忘记怎么问的,直接说不会,只用了DeepEqual,简单讲了DeepEqual)
29、Redis基本数据结构
30、Redis的List用过吗?底层怎么实现的?知道但是没用过,不知道怎么实现
31、Mysql的索引有几种,时间复杂度
32、InnoDb是表锁还是行锁,为什么(这里答不出来为什么,只说了行锁)
33、Go的channel(有缓冲和无缓冲)
34、退出程序时怎么防止channel没有消费完,这里一开始有点没清楚面试官问的,然后说了监听中断信号,做退出前的处理,然后面试官说不是这个意思,然后说发送前先告知长度,长度要是不知道呢?close channel下游会受到0值,可以利用这点(这里也有点跟面试官说不明白)
35、用过什么消息中间件之类吗?没有
36、有什么问题吗?评价?后面还有面试,后面再问吧
38、生产者消费者模式,手写代码(Go直接使用channel实现很简单,还想着面试官会不会不让用channel实现,不用channel的可以使用数组加条件变量),channel缓冲长度怎么决定,怎么控制上游生产速度过快,这里没说出解决方案,只是简单说了channel长度可以与上下游的速度比例成线性关系,面试官说这是一种解决方案
39、手写循环队列
40、写的循环队列是不是线程安全,不是,怎么保证线程安全,加锁,效率有点低啊,然后面试官就提醒Go推崇原子操作和channel
41、写完代码面试官说后面问的问题回答就可以,不知道的话没关系
42、Linux会不会,只会几个命令,面试官就说一共也就一百多个命令
43、TimeWait和CloseWait原因
44、线段树了解吗?不了解,字典树?了解
45、看过啥源码,nsq(Go的消息中间件),简单问了我里面的waitgroup包证明我看过
46、sync.Pool用过吗,为什么使用,对象池,避免频繁分配对象(GC有关),那里面的对象是固定的吗?不清楚,没看过这个的源码
47、有什么问题吗?评价?基础不错,Linux尚缺,Go的理解不够深入,高级数据结构不了解,优点是看源码
48、后面面试官讲了他们做的东西,主要是广告部分,说日均数据量至少百万以上,多达上亿,高并发使用Go支撑,有微服务,服务治理,说我需要学的东西挺多的
49、证明二叉树的叶子节点跟度数为2的节点的关系
50、唯一索引和主键索引
51、智能指针
52、字符串解析为数字(考虑浮点型)
53、单点登录,tcp粘包
54、手写洗牌
55、处理粘包断包实现,面试官以为是negle算法有关,解释了下negle跟糊涂窗口综合征有关,然后面试官觉得其他项目是crud就没问了
56、goroutine调度用了什么系统调用,这个不会,面试官想从go问到操作系统,然后以为*作系统基础不好,就问了操作系统问题
57、进程虚拟空间分布,全局变量放哪里?答上来了,操作系统就不问了
58、有没有网络编程,有,怎么看连接状态?netstat,有哪些?ESTABLISHED,LISTEN等等,有异常情况吗?TIME_WAIT很多,为什么?大量短链接
59、几种基本排序算法说一下,问了堆的时间复杂度,稳定性,为什么不稳定
60、 topk问题,海量数据topk(回答成切分多次加载内存,然后用维持k长度的有序链表,然后被说时间复杂度不好,提示说还是用堆,然后哦哦哦对)最长连续字串和,这里我说的解决方案没用dp(对dp不熟),面试官一直引导我dp,还是不会
61、什么是主键
62、联合索引和唯一索引
62、越多的索引越好吗?
63、建立索引要注意什么?
64、进程和线程区别?
65、死锁?
66、tcp三次握手
67、http,https
68、状态码401,301,302,201
69、项目我说只有一台机子,所以用的单机部署,面试官说单机也可以部署多个,有什么方法吗?我说docker,问docker有哪些网络,不熟,dockerfile关键字,只答几个。顺便扯了下nginx转发。
70、数据库隔离级别,提交读会造成什么
71、go调度
72、 goroutine泄漏有没有处理,设置timeout,select加定时器
73、mysql高可用的方案
74、进程线程区别
75、排序算法以及时间复杂度
76、怎么学习go
77、go的线程,给他讲了跟goroutine调度
78、io模型,同步阻塞,同步非阻塞,异步
79、cookie和session
80、接口kps测试
81、redis排行榜数据结构(跳跃表),查询时间复杂度
82、redis分布式,如何减少同步延迟
83、mysql能实现redis的功能吗
84、平时怎么学习?
85、看什么书?
86、兴趣爱好
87、看过google四篇分布式论文吗,没看过
89、cap理论,举例
90、LRU算法,LFU
91、讲讲怎么理解网络编程
92、go使用踩过什么坑(for range,数据库连接defer close)
93、go优缺点
95、go的值传递和引用
96、慢查询
97、为什么使用pg
98、redis的数据类型
99、所有左叶子节点的和
100、m个n大小的有序数组求并集,一开始是2路归并,求时间复杂度,后来在面试官提醒直接m路归并,求时间复杂度
101、static关键字,还有其他关键字吗
102、hash表设计,线程安全?
103、 线程自己独享什么
104、网络编程过程
105、select、epoll106、看什么书
107、排行榜怎么实现
108、go的锁如何实现,用了什么cpu指令
109、go的runtime如何实现
110、看过sql的连接池实现吗
111、ctx包了解吗?有什么用?
112、go什么情况下会发生内存泄漏?(他说ctx没有cancel的时候,这个真不知道)
113、怎么实现协程完美退出?
114、智力题:1000瓶酒中有1瓶毒酒,10只老鼠,7天后毒性才发作,第8天要卖了,怎么求那瓶毒酒?
115、简单dp题,n*n矩阵从左上角到右下角有多少种走法(只限往下和往右走)
116、用channel实现定时器?(实际上是两个协程同步)
117、go为什么高并发好?讲了go的调度模型
118、操作系统内存管理?进程通讯,为什么共享存储区效率最高
119、实现一个hashmap,解决hash冲突的方法,解决hash倾斜的方法
120、怎么理解go的interface
121、100亿个数选top5,小根堆
122、数组和为n的数组对
123、最大连续子数组和
124、redis容灾,备份,扩容
125、跳跃表,为什么使用跳跃表而不使用红黑树
126、输入url后涉及什么
127、tcp怎么找到哪个套接字
128、ipc方式,共享存储区原理
130、进程虚拟空间布局
131、进程状态转换
132、线程的栈在哪里分配
133、多个线程读,一个线程写一个int32会不会有问题,int64呢(这里面试官后来说了要看数据总线的位数,32位的话写int32没问题,int64就有问题)
134、判断二叉树是否为满二叉树
135、lru实现
136、一个大整数(字符串形式表示的),移动字符求比它大的数中最小的
137、点赞系统设计
算法题,要求给出最优解,计算时间复杂度和空间复杂度:
- 3个有序数组排列
- K个有序数组排列,(此题解法是堆排序)
基础题:
操作系统上电启动到运行init进程执行前做了什么?
(1)开机BIOS自检,加载硬盘。
(2)读取MBR,进行MBR引导。
(3)grub引导菜单(Boot Loader)。
(4)加载内核kernel。
(5)启动init进程,依据inittab文件设定运行级别)
- 系统中断机制以及运用
这个简单说下软中断、硬中断、寄存器保存、替换等等。例子包括常见的系统调用socket、read。
- 进程、线程、协程区别以及常见进程IPC方式及其实现原理
进程:操作系统分配资源的基本单位。
线程:操作系统调度的基本单位。
协程:有应用层自己负责调度器实现。优点:调度开销小。
常见IPC:共享内存、套接字、信号量、管道、消息队列。
- c++ 11智能指针内存管理方式和Golang的GC
这个说了引用计数,然后聊到内存分配的两级配置器。GC不了解。
- c++11 智能指针的循环引用怎么解决。
两种方式。1,调用reset主动释放。2. 使用弱引用weak_ptr
- docker和虚拟机区别?
轻量级。docker提供虚拟容器,虚拟机提供整个操作系统。
- TCP的可靠机制?
停止等待、滑动窗口、拥塞控制。接着谈谈拥塞控制四个算法。
- 网页上访问HTTP发生了什么?
DNS、创建网络连接、ARP、三次握手;HTTP协议封装等等顺着顺序说就行了。
- 描述竞态以及死锁并举例
指多个任务单元同时访问同一个资源,就会出现并发,竞态的现象。
- c/c++ 未定义行为是什么样子?举例
此题没搞懂,未定义的行为怎么去定义,不应该是随机的吗?
- 讲讲bootloader和image
知道不多,没有说。
- 讲讲Linux分区和挂载
岗位不同,没说。
- 谈谈Linux文件系统
知道不多,没说。
- 翻译一段英文文章,看了下,内容涉及多线程这一块。
pass。
- 动态规划的三个必要条件。
最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。
无后效性。即子问题的解一旦确定,就不再改变,不受在这之后、包含它的更大的问题的求解决策影响。
子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。
整体上偏向底层技术,难度中等,有深度,不要求全会,但是会的部分能够搞懂原理最好。
算法题给了个双指针算法,扩展题没想到堆排序。
基础题回答了大部分,涉及驱动部分知识没有讲,也不会。之前准备的redis、mongodb、kafka倒是一点没问,整个面试给人感觉良好,有所得,没有浪费时间。
极客时间Go工程师零基础就业班 - 项目实战
package handler
import (
dblayer "../../filestore-server/db"
"../../filestore-server/util"
"fmt"
"io/ioutil"
"net/http"
"time"
)
const (
pwdSalt = "*#520"
)
// 处理用户的注册请求
func SignupHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
data, err := ioutil.ReadFile("./static/view/signup.html")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Write(data)
return
}
// 参数校验
r.ParseForm()
username := r.Form.Get("username")
password := r.Form.Get("password")
if len(username) < 3 || len(password) < 5 {
w.Write([]byte("invalid parameter"))
return
}
encPassword := util.Sha1([]byte(password + pwdSalt))
suc := dblayer.UserSignup(username, encPassword)
if suc {
w.Write([]byte("SUCCESS"))
} else {
w.Write([]byte("FAILED"))
}
}
// 用户登录
func SigninHandler(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
password := r.Form.Get("password")
encPasswd := util.Sha1([]byte(password + pwdSalt))
// 1. 校验用户名及密码
pwdChecked := dblayer.UserSignin(username, encPasswd)
if !pwdChecked {
w.Write([]byte("FAILED"))
return
}
// 2. 生成访问凭证(token)
token := GenToken(username)
upRes := dblayer.UpdateToken(username, token)
if !upRes {
w.Write([]byte("FAILED"))
return
}
// 3. 登录成功后重定向到首页
resp := util.RespMsg{
Code: 0,
Msg: "OK",
Data: struct {
Location string
Username string
Token string
}{
Location: "http://" + r.Host + "/static/view/home.html",
Username: username,
Token: token,
},
}
w.Write(resp.JSONBytes())
}
// 查询用户信息
func UserInfoHandler(w http.ResponseWriter, r *http.Request) {
// 1. 解析请求参数
r.ParseForm()
username := r.Form.Get("username")
// 2. 拦截器校验token
// 3. 查询用户信息
user, err := dblayer.GetUserInfo(username)
if err != nil {
w.WriteHeader(http.StatusForbidden)
return
}
// 4. 组装并且响应用户数据
resp := util.RespMsg{
Code: 0,
Msg: "OK",
Data: user,
}
w.Write(resp.JSONBytes())
}
// 生成token
func GenToken(username string) string {
// 40位字符:md5(username+timestamp+token_salt)+timestamp[:8]
ts := fmt.Sprintf("%x", time.Now().Unix())
tokenPrefix := util.MD5([]byte(username + ts + "_tokensalt"))
return tokenPrefix + ts[:8]
}
// IsTokenValid : token是否有效
func IsTokenValid(token string) bool {
if len(token) != 40 {
return false
}
// TODO: 判断token的时效性,是否过期
// TODO: 从数据库表tbl_user_token查询username对应的token信息
// TODO: 对比两个token是否一致
return true
}
资源链接: https://pan.baidu.com/s/1Qq3F... 提取码: kczq
作者-\/ 307570512
\/ itspcool 交流学习