5/4 清华毕业:今年的暑期实习很不乐观···
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 14 分钟
阅读:.. 评论:..
今天有个清华的粉丝在群里发出一个感叹:今年暑期实习的形势不太乐观,互联网大厂的招聘门槛越来越高,竞争压力前所未有。
实习招聘曲折
他认识的同学拿到的互联网大厂offer主要集中在美团、阿里、腾讯这三家。他也跟我分享了自己的的春招经历。
美团虽然开放岗位早,但流程快速之下隐藏的是无数的不确定性,经常被鸽。而且算法和后端非常卷,很多岗位甚至早就招满了,没相关实习经历基本很难过面试,而前端、客户端、测开则相对好很多;
阿里的多轮笔试虽给了多次尝试的机会,但实际可供选择的名额有限;
但除了淘天和蚂蚁,别家hc可能都不太多。对于每家都投的大佬,应该能拿一堆offer,其他同学就只能等大佬流程结束释放hc;
而在腾讯,即使号称有5000个hc,但摆在面前的却是无数的“KPI面”,转正的过程也必然充满了激烈的竞争。
挂了就等着别的事业群来捞,可以当成面试模拟器,我有认识已经来来回回面了十几次的同学;
字节跳动的kpi面和泡池子,快手的无限复活赛,拼多多的高门槛笔试,以及小红书和网易雷火的苛刻要求,都让人在兴奋和希望之间感受到一丝忧愁和折磨。
米哈游是我一直心心念念的梦厂,进了面试,一面答得不好开始泡池子,面试官觉得我经验还不够。米哈游网上全是招人贴,但最终进面试的都不多,拿offer的一共也没看到几个。
我推了几个同学的简历到百度实习的组,给的不多但是要求还高,我服了。
总而言之,互联网大厂现在基本不差人了。连具备丰富经验的员工也面临着被裁撤的风险,更不用说新人了。
尽管你可能拥有良好的学历和经验背景,但如果投递简历的时间稍晚,机会也会相应减少。
不过没有面上的时候,千万不要放弃摆烂,因为一旦放弃,机会就真的无影无踪了;相反,应该更加努力地准备面试,积累项目经验。
此外,不妨考虑中小型企业,或者探索互联网行业之外的其他领域。
对于计划参加秋招或明年夏季实习的同学,建议要么提前做好准备尽早投递简历,要么耐心积累实力,等待时机来临时抓住机会。
面经分享
为了帮助大家更好的理解面试,我们今天来看一篇腾讯PCG的模拟面试。 面试官: 首先,请介绍一下你自己,以及你喜欢做的技术方向。
求职者: 当然,我是一个对计算机科学充满热情的学生。特别对后端开发感兴趣,我喜欢深入了解系统如何运作,以及怎样通过优化算法来提升性能。
面试官: 很好。你了解过QUIC协议吗?可以介绍一下吗?
求职者: 是的,**QUIC(Quick UDP Internet Connections)**是一种基于UDP实现的传输层网络协议,它减少了连接和传输的延迟,支持多路复用,并且内置了TLS加密功能。
面试官: 那你觉得QUIC一定比TCP更好吗?
求职者: 并不是绝对的。虽然QUIC在多路复用和减少延迟方面比TCP有优势,但TCP因其广泛的应用和成熟的优化,在网络环境较差或者需要严格顺序传输的场景中可能更可靠。
面试官: 那如何实现在切换网络时仍能无缝连接呢?
求职者: QUIC实现无缝切换主要依赖于它的连接ID功能,它允许即使IP地址变化,连接也能保持不断,因为QUIC连接是由连接ID而不是传统的四元组来标识的。
面试官: 在实习中,你使用C++实现了反射,这主要用于什么?
求职者: 在我的实习项目中,使用C++实现反射主要是为了提高代码的可扩展性和可维护性。它允许程序在运行时查询和修改对象的状态和行为,这在处理不同类型的对象时非常有用。
面试官: 解释一下Epoll和select的区别。
求职者: Epoll相比于select,最大的区别在于它的效率更高。select在处理大量文件描述符时,性能会显著下降,因为它每次调用都需要从用户态拷贝文件描述符到内核态。而epoll使用事件通知机制,只有活跃的文件描述符才会被处理,减少了不必要的拷贝和轮询。
面试官: 那在切换到内核态时会保存哪些信息?
求职者: 切换到内核态时,操作系统会保存当前进程的上下文信息,包括程序计数器、寄存器状态、内存状态等,以便在切回用户态时能恢复执行。
面试官: Epoll边缘触发时是使用阻塞还是非阻塞的,为什么?
求职者: 边缘触发通常和非阻塞I/O一起使用,因为这样可以避免I/O操作阻塞进程,同时确保只有数据状态发生变化时才会通知应用程序。
面试官: 如果使用非阻塞的方式,如何保证收集完数据呢?
求职者: 使用非阻塞方式时,可以通过循环读取数据直到返回EAGAIN错误,这样就可以确保数据被完全收集。
面试官: 谈谈MySQL事务特性。
求职者: MySQL事务的特性包括ACID,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
面试官: 你刚才提到了ACID,它们是怎么保证的?
求职者: 原子性通常通过undo log来保证,一致性通过事务的原子性和隔离性来保证,隔离性通过锁机制和MVCC来实现,持久性则通过redo log来确保事务一旦提交,即使系统崩溃,数据也不会丢失。
面试官: 那么undo log是怎样工作的?
求职者: undo log是用来记录事务发生之前的数据状态,如果事务需要回滚,它可以用来恢复数据到事务开始前的状态。
面试官: 怎么优化SQL语句?你有遇到过很慢的SQL语句吗?
求职者: 优化SQL语句可以从多个角度入手,比如选择合适的索引、优化查询逻辑、减少不必要的表连接等。我有遇到过慢查询,通过分析执行计划和调整索引来解决。
面试官: 索引怎么加?除了select语句,还有其他的SQL语句吗?
求职者: 索引通常加在查询中频繁使用的列上,特别是在WHERE子句和JOIN操作中的列。除了select语句,还有insert、update和delete等SQL语句。
面试官: MySQL有哪些锁?
求职者: MySQL中的锁包括共享锁(S锁)、排他锁(X锁)、意向锁(Intention Locks)和行级锁(Row-Level Locks)等。
面试官: Python有哪些数据结构?
求职者: Python中的数据结构包括列表、字典、元组、集合等。
面试官: Python怎么调用C语言的代码?
求职者: 可以使用Python中的ctypes库或者Cython来调用C语言代码。
面试官: Redis中的雪崩和击穿是什么?
求职者: 缓存雪崩是指大量缓存同时失效,可能导致数据库请求量骤增;而缓存击穿是指缓存中没有但数据库中有的数据,被频繁访问,导致数据库压力过大。
面试官: Redis进行查询状态是同步还是异步的查询?
求职者: Redis的查询通常是同步进行的,客户端发出请求,服务器处理后返回结果。
面试官: 同步和异步有什么区别呢?
求职者: 同步操作是阻塞的,即发出调用后要等待结果返回;而异步操作是非阻塞的,发出调用后不必等待结果,可以继续执行其他任务。
面试官: 你写过Go语言吗?
求职者: 我没有实际项目经验,但我对Go语言的基础语法和特性有初步了解。
面试官: C++中堆和栈有什么区别?
求职者: 栈是用于存储局部变量和函数调用的内存区域,由编译器自动管理;而堆是用于存储动态分配的对象,需要程序员手动管理内存的分配和释放。
面试官: STL容器内存是怎么管理的?
求职者: STL容器如vector、list等内部通常有自己的内存分配器,可以根据容器的大小动态地分配和释放内存。
面试官: 那vector的扩容原理介绍一下。
求职者: 当vector中的元素超过当前分配的容量时,它会申请一个更大的内存空间,通常是当前大小的两倍,然后将所有元素复制到新的内存空间,释放旧的内存。
面试官: 好的,现在让我们来看一下算法题。那我们先来解决合并区间的问题。假设给你一系列区间,请你编写一个函数,合并所有重叠的区间,让我看看你的思路和代码实现。
求职者: 好的。我们用数组 merged 存储最终的答案。 首先,我们将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 merged 数组中,并按顺序依次考虑之后的每个区间: 如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 merged 的末尾; 否则,它们重合,我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点,将其置为二者的较大值。以下是代码实现:class Solution { public int[][] merge(int[][] intervals) { if (intervals.length == 0) { return new int[0][2]; } Arrays.sort(intervals, new Comparator<int[]>() { public int compare(int[] interval1, int[] interval2) { return interval1[0] - interval2[0]; } }); List<int[]> merged = new ArrayList<int[]>(); for (int i = 0; i < intervals.length; ++i) { int L = intervals[i][0], R = intervals[i][1]; if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) { merged.add(new int[]{L, R}); } else { merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R); } } return merged.toArray(new int[merged.size()][]); } }
面试官: 非常清晰。现在让我们来看看硬币兑换问题。给定不同面额的硬币和一个总金额,编写一个函数来计算可以凑成总金额所需的最少的硬币个数,如果没有任何一种硬币组合能组成总金额,返回-1。
求职者: 这个问题可以通过动态规划来解决。我会创建一个数组来保存每个金额所需的最少硬币数,初始除了金额0外,其他金额所需硬币数都设为一个大数。然后,我会遍历每种硬币,更新每个金额所需的最少硬币数。这样,当遍历完所有硬币后,数组中的最后一个元素就是答案。以下是代码实现:public class Solution { public int coinChange(int[] coins, int amount) { int max = amount + 1; int[] dp = new int[amount + 1]; Arrays.fill(dp, max); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } }
面试官: 很好,这是一个经典的动态规划问题,你的解法很标准。那我们现在回到数据库,谈谈你对MySQL事务特性的理解。
求职者: 在MySQL中,事务特性指的是事务的ACID特性。原子性确保了事务中的操作要么全部完成,要么全部不执行;一致性保证了事务的执行不会破坏数据库的完整性和一致性规则;隔离性表示一个事务的执行不会被其他事务干扰;持久性则确保了一旦事务提交,其结果就是永久的。
面试官: 那么ACID中的四大特性是怎么保证的?
求职者: 原子性通过事务日志中的undo log来保证,如果事务失败,可以通过undo log来回滚到事务开始前的状态;一致性通过数据库管理系统确保,比如通过约束和触发器来维护;隔离性通常通过锁机制和MVCC(多版本并发控制)来实现;而持久性则是通过redo log来实现的,确保了事务提交后的改变即使在系统崩溃后也不会丢失。
面试官: 既然提到了undo log,那你能详细介绍一下它的作用吗?
求职者: undo log是用来记录事务执行前的数据状态,如果事务执行失败或者需要回滚,它可以恢复数据到事务开始前的状态。这样就可以保证即使在事务执行过程中出现错误,数据库也能保持一致性。
面试官: 好的,那如何优化SQL语句?你有没有遇到过很慢的SQL语句?
求职者: 优化SQL语句通常从以下几个方面入手:分析查询语句的执行计划,使用合适的索引,优化查询条件,减少不必要的JOIN操作等。我曾经遇到过因为缺乏索引而执行缓慢的SQL语句,通过添加适当的索引,查询速度得到了显著提升。
面试官: 那么索引是怎么添加的?除了SELECT语句,还有哪些其他的SQL语句?
求职者: 索引通常是添加到表中查询频繁的列上,可以通过CREATE INDEX
语句来创建。除了SELECT语句,还有INSERT、UPDATE和DELETE等DML语句,以及CREATE TABLE、ALTER TABLE等DDL语句。
面试官: MySQL中有哪些锁?
求职者: MySQL支持多种锁,包括表级锁、行级锁和页面锁。其中行级锁可以提供最高的并发处理能力,但管理开销也最大。
面试官: Python中有哪些数据结构?
求职者: Python中常见的数据结构包括列表(list)、字典(dict)、**集合(set)和元组(tuple)**等。
面试官: Python怎么调用C语言的代码?
求职者: Python可以通过ctypes模块或者C扩展来调用C语言代码。ctypes提供了与C语言库交互的能力,而C扩展则需要编译成动态链接库或模块。
面试官: Redis中的雪崩和击穿是什么?
求职者: 缓存雪崩是指在缓存层面大量的key同时过期,可能导致瞬间对数据库请求量的激增;缓存击穿则是指大量并发请求查询一个key时,这个key刚好失效,导致所有请求都落到数据库上。
面试官: Redis查询状态是同步还是异步的?
求职者: Redis的查询通常是同步的,它会处理完请求后返回结果给客户端。
面试官: 那么,同步和异步有什么区别?
求职者: 同步操作要求调用者等待操作完成,而异步操作则不需要等待,可以在操作完成后通过回调或者事件来通知调用者。
面试官: 既然我们谈到了Go,你有写过Go语言吗?
求职者: 我没有在项目中使用过Go语言,但我对它的语法和一些基本特性有所了解。
面试官: 谈谈C++中堆和栈的区别。
求职者: 在C++中,栈是用来存储函数调用和局部变量的,它是自动管理的;而堆是用来存储动态分配的内存,需要程序员手动申请和释放。
面试官: STL容器是如何管理内存的?
求职者: STL容器通常使用模板化的分配器来管理内存,这些分配器能够根据容器的需求动态地分配和释放内存。
面试官: 最后,vector的扩容原理是怎样的?
求职者: 当vector需要增长超过其当前容量时,它会分配一块新的内存,通常是现有容量的两倍,并将现有元素复制到新内存中,然后释放旧内存。
面试官: 很不错,今天面试就到这。等消息吧。