阿里云游戏一点五面
- 自我介绍
- 华为实习工作
- 问了开发过哪些规则
- 定义变量没有初始化会发生生么事
- 对写代码怎么看
- 对35岁还在写代码没什么出息怎么看
- 自己的规划
- 5年内的规划
- 觉得哪个项目有亮点
- 讲了编译器的项目
- 项目由哪几个模块组成,有哪些难点
- 对编译原理的理解
- 对业务和技术的看法以及倾向
- 业务就是按照来的需求写功能
- 抖音电商的offer和阿里云编译的offer选哪个
- 对硬件和芯片的看法和兴趣
- ACM竞赛的经历
- 比赛的过程是什么样子
- 做了哪些贡献
- 有什么收获
- 反问环节
- 问了面试的进度是什么样子,因为后台看不到
总结:一共差不多30分钟,没问太多八股文,主要是问了项目实习以及聊了一些规划和看法之类的。上一次不算一面,只算做意向评估,这次的能算一面吧,后面还有一到两轮技术面,还要HR面,以及笔试挺难的也挺重要的。认为我的优势是ACM经历所以笔试要好好准备。
腾讯微信客户端开发一面
已通过
上来先手撕三道代码, 题目不难,都算是经典题,但是给的时间稍微有点儿少,而且一上来就撕代码有点儿懵,导致一道很简单的链表翻转题没做好。。
第一题是链表k个一组翻转
- 一上来有点懵,边界老是处理不好,写了十分钟没写出来就去做后面两道题了,后面两道题比较简单,一会儿就写完了又回来接着做这个。
- 老是处理不好边界,索性直接把链表存到数组里,在数组里处理,结果最后面试让解释一下代码的时候还是解释的不太清楚。。
第二题是把数组的前k个移到最后
- 开了个临时数组存,面试官问不定长数组会有什么问题,如果数组很长那么存在哪里
- 问有没有更小内存开销的方法,问复杂度(这里答得有点儿混乱)
- 堆栈的区别
- 为什么要有堆和栈
第三题是最大子数组
问ACM竞赛经历,团队几人,怎么分配工作,过几题能拿牌
问编译器项目,非常详细,一步一步地问
- 词法分析怎么实现的,有没有比字符串匹配更好的方法,答了字典树,又问字典树为什么更好之类的
- 文法分析,抽象语法树,递归实现,有没有比递归实现更好的方式,答了可以模仿字典树(这里答的不好,面试官说循环递归的问题字典树解决不了,就建不起来这棵树),除了递归和字典树之外还有没有什么方案(不知道。。)
- 汇编代码生成是干什么的,为什么是四元式,解释了一下操作数操作符操作结果之类的。
- 寄存器优化怎么实现的,答了引用计数法,问还有哪些地方会用到(内存页面置换),然后问了一些内存页面置换的问题
虚拟内存,为什么要有虚拟内存,怎么实现的,页表,页和块
进程间通信有哪些,管道是什么,套接字是什么,共享内存是什么,哪个最快(答了共享内存,不知道对不对)
线程同步方式,信号是什么
为什么要有线程,进程是什么
B+树是什么,有什么特性(答了叶子结点之间有指针),有什么好处(答了查找比较快和擅长范围查找)
TCP和UDP,区别,适用于哪些场景
HTTPS是什么,SSL具体怎么实现,为什么,对称加密和非对称加密的区别
问科研项目
- 持续时间,几个人在做,具体怎么实现,除了超声还有什么方式,wifi可以吗,红外可以吗,摄像头人脸识别怎么样,呼吸和心跳是怎么测得的等等
问了开发的app,觉得哪个最好,讲了一下
工作地点是广州,对于工作地点有没有想法
反问环节
- 问了面试官觉得我表现怎么样,有哪些方面可以提高,面试官说原理性的东西可以提高一下,比如做的编译器的原理细节等,思考更深入一点儿
总结:问了一个半小时多,是这么多面试里最久的,期间网络很差,换手机热点也很差,断线好几次,后来直接把摄像头关了。面试官问的特别详细,特别深,特别喜欢问为什么。知识点八股文方面答的还行,但是手撕代码和问项目这两个部分出了不少问题,感觉要gg了。。
阿里云游戏一面
接到继续面试的电话了,应该算是过了吧
电话面
自我介绍
问华为的实习经历
做了什么工作,技术难题,工具开源
规则应用于十万行代码的性能?误报率?华为代码安全重复率啥的。。(这些都不了解。。)
问科研项目
系统架构,项目持续时间,从事的工作,硬件组成
团队介绍
原神等的云游戏,可能会跟硬件相关,中心云芯片,高通
进程同步和线程同步
进程同步
管道
管道分为命名管道和匿名管道,命名管道可以用于两个或任意多个进程间通信,匿名管道则只能用于有血缘关系(父子进程、兄弟进程、爷孙进程等)的进程间通信。Linux中的“|”命令就是匿名管道,表示把一个进程的输出作为另一个进程的输入。管道就是内核里的一段缓存,从管道一端写入的数据实际上是缓存在内核中,从另一端读取也就是从内核中读取这段数据。管道是半双工的,数据只能向一个方向流动,双方需要互相通信时,需要建立起两个管道。
消息队列
多个不相干的进程可以通过一个消息队列来传递数据,且传递的是一个有意义的数据结构,而管道只能传递没有意义的字节流,还需要在接收端做解析。
共享内存
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的一种IPC方式,因为没有内存拷贝的操作,但需要依靠互斥锁或信号量来实现同步。
socket
可用于不同主机之间的进程间通信。
信号
信号是Linux系统中的进程间通信方式,信号可以在任何时候发给某一进程,用于通知该进程某个事件已经发生。比如kill -9命令就可以向指定的进程发送一个终止信号从而杀死进程。
信号量
信号量本质就是一个计数器,记录资源能被多少个进程同时访问,用来实现进程之间的互斥与同步,信号量的引入的是为了解决共享内存通信方式造成的进场安全问题。
进程同步和进程通信
进程同步是进程之间按照一定顺序执行,进程通信是进程之间传输信息。
进程通信是一种手段,而进程同步是目的。即为了达到进程同步的目的,需要让进程进行通信,传输一些同步所需要的信息。
线程同步
互斥锁
互斥锁是线程同步最常用的一种方式,通过互斥锁可以锁定一个代码块,对于被锁定的这个代码块,所有的线程只能串行处理,不能并行处理。
读写锁
读写锁是互斥锁的升级版,所有线程的读操作都是并行的,只有写操作是串行的。程序中的读操作越多,读写锁性能就越高,相反,若程序中全是写操作,那么读写锁会退化成互斥锁。
条件变量
条件变量的主要作用不是处理线程同步,而是进行线程的阻塞。常常和互斥锁一起用在生产者和消费者模型中。举个例子:当任务队列为空时,消费者无法消费,使用条件变量把消费者线程阻塞住,等待生产者生产出任务后,再唤醒一个或多个被条件变量阻塞的消费者线程;反过来也可以控制生产者生产的上限,当任务队列达到一个上限值时用条件变量阻塞住生产者线程,直到消费者把任务消费后再唤醒被条件变量阻塞的生产者线程。
信号量
信号量可以实现线程同步也可以实现进程同步,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。信号量主要阻塞线程,不能完全保证线程安全,如果要保证线程安全,需要和互斥锁一起使用。信号量也可以用来实现生产者消费者模型,在用条件变量实现生产者消费者模型时需要自己做条件判断,而使用信号量就不需要。举个例子:初始化生产者的信号量为5,消费者的信号量为0,因为消费者信号量为0所以会被阻塞,生产者进行一次生产后会将自己的信号量减1,将消费者信号量加1,这时消费者解除阻塞,进行消费后再将自己的信号量减1生产者信号量加1。
自旋锁
自旋锁与互斥锁类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。自旋锁可用于一下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多成本。
屏障
屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从该点继续执行。pthread_join函数就是一种屏障,允许一个线程等待,直到另一个线程退出,但屏障允许任意数量的线程等待,直到所有的线程完成处理工作,而线程不需要退出,所有线程达到屏障后可以接着工作。
信号量和互斥锁
- 互斥锁是由一个线程持有的,加锁和解锁操作在一个线程中执行。而信号量可以由不同线程进行PV操作。
- 互斥锁用于控制多个线程对于一个共享资源的互斥访问,而信号量用于协调多个线程对于一系列资源的访问。
- 信号量本质上是一个计数器,其正值代表资源的可用数量,负值代表还有多少个线程在等待资源。
条件变量和信号量
- 信号量利用条件变量、互斥锁、计数器实现,计数器就是信号量的核心,信号量是条件变量的高级抽象。
- 使用条件变量可以一次唤醒所有等待者,而这个信号量没有的功能,感觉是最大区别。
- 信号量是有一个值(状态的),而条件变量是没有的,没有地方记录唤醒(发送信号)过多少次,也没有地方记录唤醒线程(wait返回)过多少次。从实现上来说一个信号量可以是用mutex + counter + condition variable实现的。因为信号量有一个状态,如果想精准的同步,那么信号量可能会有特殊的地方。信号量可以解决条件变量中存在的唤醒丢失问题。