躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发
早春二月,研发倍忙,杂花生树,群鸥竟飞。为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让2023年的第一个Offer来的比以往快那么一点点。
打开某垂直招聘平台,寻找2023年的第一个猎物:
投递简历之后,如约进行面试。
笔试题
正规公司的面试一般都是笔试先行,笔试题的作用非常务实,就是直接筛掉一批人,提高面试效率,需要注意的是,在这个环节中,往往无法用搜索引擎进行检索,所以,你的大脑就是Python解释器,你的笔将会代替程序的输出:
# 实现字符串反转,以逗号作为切割符,切割的子串以单词作为单元反转
# 输入:hello world, god bless you
# 输出:world hello, you bless god
这道题网上没有原题,但其实并不难,考点在于应聘者对于Python基础和复合数据类型内置方法的熟悉程度,题目中所谓的字符串反转并不是真正意义的字符串反转,而是以单词为单元的反转,同时加入了逗号分割逻辑,所以只要对字符串内置方法split,rstrip和列表内置方法join以及reverse的用法足够了解,就可以直接写出解法:
def reseverWords(s:str) -> str:
all_str = ""
s = s.split(',')
for x in s:
lis= x.split()
lis.reverse()
all_str += ' '.join(lis)+', '
all_str=all_str.rstrip(', ')
return all_str
print(reseverWords(str1))
第二题是SQL语句题目,请写一条sql,按照地区的分组聚合数据进行排序:
id name location
-- ----- --------
1 Mark US
2 Mike US
3 Paul Australia
4 Pranshu India
5 Pranav India
6 John Canada
7 Rishab India
排序后结果:
id name location
-- ----- --------
4 Pranshu India
5 Pranav India
7 Rishab India
1 Mark US
2 Mike US
3 Paul Australia
6 John Canada
这道题也无法在网上查证,一般的分组聚合只是查一个数,这个是按照数量进行排序,并且其实并不展示数量,也可以理解为展示的为分组数据的明细排行榜:
SELECT x.*
FROM my_table x
JOIN (SELECT location, COUNT(*) total FROM my_table GROUP BY location) y
ON y.location = x.location
ORDER
BY total DESC
, id;
思路是先分组,随后按照分组的聚合数据根据地区字段连表排序即可。
自我介绍
通过笔试题筛选后,进入自我介绍环节,一般介绍技术栈和简单的项目经历即可,参考示例:
您好(下午好/上午好),我是19年毕业的,在RD(Research and Development engineer即研发工程师岗位)岗差不多有三年左右的工作经验,一开始在一家创业型公司起步,当时主力开发语言是python,,使用mtv架构,在公司主要和业务打交道,开发和维护后台的API,大概沉淀了两年左右吧,我跳槽到了第二家公司,薪酬实现了double,在新的技术团队里,我接触到了前后端分离项目,也学习了异步编程思想,主力框架是tornado,前端技术也有所涉猎,比如vue框架,了解了数据双向绑定理念,同时也学习了在业务解耦和服务封装层面比较流行的docker容器技术,这项技术使我平时开发和测试工作都提高了效率,最近一年左右吧,我经常使用的web框架是tornado,这个框架我个人非常喜欢,它的异步非阻塞特性让我对异步编程思想的认识更深入了。我也尝试过remote这种工作形式,也锻炼了我在团队中的沟通能力,其实三四年下来,做过的东西解决过的问题也挺多的,待过大团队也经历过小团队,给我的感觉就是互联网企业随着发展,技术和行业边界其实是越来越模糊的,也就是说技术都是具有相通性的,我个人来讲,优势就是技术涉猎比较广,前后端都接触过,踩得坑也比较多,在特定领域有一定的深入,比如异步编程这块。另外我觉得搞开发的,学习能力,总结能力很重要,所以我一直保持着写技术博客的习惯,这样经过沉淀,可以提高一个人的分析能力,也就是解决问题的能力,我的介绍完了,谢谢。
进程、线程和协程的区别
进程、线程和协程,从来就是Python面试中聚讼不休的一个话题,只要我们还在使用Python,就一定逃离不了三程问题:
进程
首先明确一下进程和线程的概念,进程系统进行资源分配的基本单位,一台机器上可以有多个进程,每个进程执行不同的程序,每个进程相对独立,拥有自己的内存空间,隔离性和稳定性比较高,进程之间互不影响,但是资源共享相对麻烦,系统资源占用相对高,同时进程可以利用cpu多核资源,适合cpu密集型任务,比如一些统计计算任务,比如计算广告转化率,uv、pv等等,或者一些视频的压缩解码任务,进程还有一个使用场景,就是后期部署项目的时候,nginx反向代理后端服务,往往需要开启多个tornado服务来支持后台的并发,就是利用了多进程的互不干扰,就算某个进程僵死,也不会影响其他进程,进程使用的是mulitprossing库 ,往往是先声明进程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定进程数的容器中(list),通过循环或者列表推导式,使用start方法开启进程,join方法阻塞主进程。
线程
线程是系统进行资源调度的最小单位,它属于进程,每一个进程中都会有一个线程,由于线程操作是单进程的,所以线程之间可以共享内存变量,互相通信非常方便,它的系统开销比进程小,它是线程之间由于共享内存,会互相影响,如果一个线程僵死会影响其他线程,隔离性和稳定性不如进程,同时,线程并不安全,如果对同一个对象进行操作,需要手动加锁,另外从性能上讲,多线程会触发python的全局解释器锁,导致同一时间点只会有一个线程运行的交替运行模式,线程适用于io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我使用多线程进行消费。线程使用的是Threading库 ,往往是先声明线程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定线程数的容器中(list),通过循环或者列表推导式,使用start方法开启线程,join方法阻塞主线程。
协程
协程是一种用户态的轻量级线程,协程的调度完全由用户控制,不像进程和线程是系统态,所以在不主动切换协程的情况下,操作全局变量的时候,可以无需加锁(这里有坑,协程库内置也是有锁的,但是看场景,如果使用场景内没有主动切换协程(await)写操作就不需要加锁,如果单协程执行过程中,主动切换了协程,写操作则需要加锁 协程是否加锁问题),只需要判断资源状态即可,效率非常高,同时协程是单线程的,即可以共享内存,又不需要系统态的线程切换,同时也不会触发gil全局解释器锁,所以它性能比线程要高。具体使用场景和线程一样,适合io密集型任务,所谓io密集型任务就是大量的硬盘读写操作或者网络tcp通信的任务,一般就是爬虫和数据库操作,文件操作非常频繁的任务,比如我负责开发的审核系统,需要同时对mysql和redis有大量的读写操作,所以我后期将多线程改造成协程进行消费。协程我使用的python原生协程库asyncio库,首先通过asyncio.ensure_future(doout(4))方法建立协程对象,然后根据当天审核员数量指定开启协程数,和多线程以及多进程的区别是,协程既可以直接传实参,也可以传不定长参数,很方便,然后通过await asyncio.gather(*tasks)方法启动协程,需要注意的是,主方法需要声明成async方法,并且通过asyncio.run(main())来启动。协程虽然是python异步编程的最佳方式,但是我认为它也有缺点,那就是异步写法导致代码可读性下降,同时对编程人员的综合素质要求高,并不是所有人都能理解协程的工作方式,以及python原生协程的异步写法。
Python中的深拷贝和浅拷贝
仅次于三程问题的明星面试题,一般情况下,大家都会说浅拷贝修改复制对象会影响原对象,而深拷贝不会,但其实,浅拷贝会有三种细分的情况:
1.拷贝不可变对象:只是增加一个指向原对象的引用,改变会互相影响。
>>> a = (1, 2, [3, 4])
>>> b = copy.copy(a)
>>> b
... (1, 2, [3, 4])
# 改变一方,另一方也改变
>>> b[2].append(5)
>>> a
... (1, 2, [3, 4, 5])
2.拷贝可变对象(一层结构):产生新的对象,开辟新的内存空间,改变互不影响。
>>> import copy
>>> a = [1, 2, 3]
>>> b = copy.copy(a)
>>> b
... [1, 2, 3]
# 查看两者的内存地址,不同,开辟了新的内存空间
>>> id(b)
... 1833997595272
>>> id(a)
... 1833997595080
>>> a is b
... False
# 改变了一方,另一方不会改变
a = [1, 2, 3] b = [1, 2, 3]
>>> b.append(4)
>>> a
... [1, 2, 3]
>>> a.append(5)
>>> b
... [1, 2, 3, 4]
3.拷贝可变对象(多层结构):产生新的对象,开辟新的内存空间,不改变包含的子对象则互不影响、改变包含的子对象则互相影响。
>>> import copy
>>> a = [1, 2, [3, 4]]
>>> b = copy.copy(a)
>>> b
... [1, 2, [3, 4]]
# 查看两者的内存地址,不同,开辟了新的内存空间
>>> id(b)
1833997596488
>>> id(a)
1833997596424
>>> a is b
... False
# 1.没有对包含的子对象进行修改,另一方关我卵事
a = [1, 2, [3, 4]] b = [1, 2, [3, 4]]
>>> b.append(5)
>>> a
... [1, 2, [3, 4]]
>>> a.append(6)
>>> b
... [1, 2, [3, 4], 5]
# 2.对包含的子对象进行修改,另一方也随之改变
a = [1, 2, [3, 4]] b = [1, 2, [3, 4]]
>>> b[2].append(5)
>>> a
... [1, 2, [3, 4, 5]]
>>> a[2].append(6)
>>> b
... [1, 2, [3, 4, 5, 6]]
高并发如何进行处理的
既然JD(Job Describe)中提到了高并发,那么就一定会问高并发问题,一般情况下,涉及高并发场景的基本上都是外部系统,此时需要简单介绍一下系统的容量是多少,比如有注册用户数、日活、QPS等等。然后就是提供具体方案,一般的手段是加缓存,数据库读写分离,数据库 sharding 等等。高并发背景下,整个系统瓶颈一般都在数据库。
除了上述的一些常规方案,业内最常用的缓解高并发的手段是使用异步任务队列:
为了解决生产者和消费者过度耦合的效率低下问题,我设计了一个缓冲区,生产者不会直接和消费者产生关系,而是通过缓冲区解耦,这个缓冲区就是异步任务队列,队列容器我采用redis数据库,因为redis性能优势比较明显,同时内置的list数据类型比较契合队列这种数据结构,工具类内置了,初始化方法,入队方法,出队方法,队列长度,以及查重唯一方法。每当商户提交表单,此时并不会修改状态,而是将表单数据入库,同时将商户uid进行入队操作,遵循fifo原则,在消费者端使用异步的方式进行消费,也就是出队操作,每一个线程对应一个审核员,通过消费方法进行传参,每次将出队的商户uid和线程传入的审核员id进行组合分配,出队之后并发数已经得到了控制,随后在mysql端进行update操作,达到异步分配审核的目的。
保持幂等性
如果面试中提到了异步任务队列(消息队列),那么幂等性操作几乎一定会在后续的问题中提及,所谓幂等性,简单来说就是对于同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,就称该操作为幂等的。比如说如果有一个接口是幂等的,当传入相同条件时,其效果必须是相同的。在RabbitMQ中消费幂等就是指给消费者发送多条同样的消息,消费者只会消费其中的一条。例如,在一次购物中提交订单进行支付时,当网络延迟等其他问题造成消费者重新支付,如果没有幂等性的支持,那么会对同一订单进行两次扣款,这是非常严重的,因此有了幂等性,当对同一个订单进行多次支付时,可以确保只对同一个订单扣款一次。
具体手段:
事实上,当审核任务出队之后,如果在消费端出现意外,这个意外包含但不限于出对后tornado宕机、mysql宕机等等,导致出队任务没有进行流程化处理,所以我采用了ack验证机制,也就是缓冲区队列从单队列升级为双队列,把rpop出队改成redis内置的rpoplpush的原子性操作,出队后立即进入确认队列,在消费端完成审核任务后,对ack队列进行确认移除操作,如此,一次审批任务才算完结,如果任务生命周期内,任务一直存在于确认队列没有出队,那么轮询任务会将任务id移出确认队列,重新在缓冲区队列进行入队操作,这样就避免了,僵审任务的问题。
结语
技术面试虽然是一种信息不对等的较量,但是只要认真研究JD(Job Describe),做好相关的知识储备,基础常识不要翻车(包含但不限于Python基础/数据库基础),那么作为应聘者拿一个Offer也不是想象中的那么难,本次面试的实战录音可以在B站(Youtube)搜索刘悦的技术博客查阅,欢迎诸君品鉴。
躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发的更多相关文章
- 春招后端阿里腾讯字节美团Offer拿来吧你,面试经验分享
近期很多童鞋在准备校招了,找了蚂蚁的一位童鞋,给大家分享一波面试经验,以及面试心得,希望能帮大家在秋招拿到一个好结果 我自己的22届春招实习算是告一段落,给自己做个总结,也给大家分享一下面试的一些心得 ...
- PHP高手干货分享:不能不看的50个细节!【PHP培训教程】
兄弟连分享PHP高手干货:不能不看的50个细节 1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以 ...
- 十面阿里,七面头条,六个Offer,春招结束
作者:jkgeekjack链接:https://www.nowcoder.com/discuss/80156?type=0&order=0&pos=13&page=2来源:牛客 ...
- 干货分享:SQLSERVER使用裸设备
干货分享:SQLSERVER使用裸设备 这篇文章也适合ORACLE DBA和MYSQL DBA 阅读 裸设备适用于Linux和Windows 在ORACLE和MYSQL里也是支持裸设备的!! 介绍 大 ...
- iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ②)
距上一篇博客"APP引导页的高度集成 - DHGuidePageHUD - ①"的发布有一段时间了, 后来又在SDK中补充了一些新的内容进去但是一直没来得及跟大家分享, 今天来跟大 ...
- iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ①)
好长时间没更新博客, 是时候来一波干货分享了;APP引导页话不多说每一个APP都会用到,分量不重但是不可缺少,不论是APP的首次安装还是版本的更新,首先展现给用户眼前的也就只有它了吧,当然这里讲的不是 ...
- 【干货分享】Google 的设计准则,素材和资源
在谷歌,他们说, “专注于用户,所有其它的就会水到渠成 ”.他们遵循设计原则,寻求建立让用户惊喜的用户体验.谷歌一直挑战自己,为他们的用户创造一种视觉语言,综合优秀设计的经典原则和创新.谷歌设计规范是 ...
- 【干货分享】Node.js 中文资料导航
这篇文章与大家分享一批高质量的的 Node.js 中文资料.Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的, 易于扩展的网络应用 Node ...
- 干货分享:MySQL之化险为夷的【钻石】抢购风暴【转载】
转自: 干货分享:MySQL之化险为夷的[钻石]抢购风暴 - Vanos_韩尛哲 - 博客园http://www.cnblogs.com/Vanos-lcp/p/5642097.html 抢购钻石不稀 ...
- 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)
32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...
随机推荐
- 记一次spark数据倾斜实践
参考文章: 大数据项目--倾斜数据的分区优化 数据倾斜概念 什么是数据倾斜 大数据下大部分框架的处理原理都是参考mapreduce的思想:分而治之和移动计算,即提前将计算程序生成好然后发送到不同的 ...
- 2. 第一个PyQt5 程序 Helloword!
专栏地址 ʅ(‾◡◝)ʃ 第一个 PyQt5 程序 2.1 import sys from PyQt5.QtWidgets import QApplication,QWidget app = QApp ...
- shell编写循环检查脚本
背景:如下脚本实现当微服务重启后,检查微服务的启动端口正常,可通过轮询的方式来实现所需要用到配置文件config.properties信息如下: onlineService:8001 algorthS ...
- 3.5:基于Python的KNN算法简单实现
〇.目标 1.使用pycharm工具创建项目demo: 2.使用python语言实现KNN算法. 一.创建脚本文件 二.编写KNN算法程序 KNN算法所阐述的核心思想在KNN.py文件的注释部分具有详 ...
- Map的遍历方式,常用的key-value遍历方式
在开发过程中经常会遇到 map 的遍历,本文将会介绍四种常用的 key-value 遍历方式 说明: 增强 for 循环遍历 先取出 map 的 keySet,进行遍历,再取出对应 key 的 val ...
- HDOJFatmouse肥鼠交易//c++控制保留小数
贪心算法.我就不贴题了//no.1009 但是我的代码运行超时了-改了好久都不对- 看别人代码,顺便学习c++控制保留小数怎么操作; 我的错误代码:(时间占用可能是多次调用findmax造成的) #i ...
- windows上用vs2017静态编译onnxruntime-gpu CUDA cuDNN TensorRT的坎坷之路
因为工作业务需求的关系,需编译onnxruntime引入项目中使用,主项目exe是使用的vs2017+qt5.12. onnxruntime就不用介绍是啥了撒,在优化和加速AI机器学习推理和训练这块赫 ...
- STM32点亮LED的代码
led.c #include "led.h" void LED_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2P ...
- formly-form 动态表单
动态表单库 https://github.com/ngx-formly/ngx-formly 安装 ng add @ngx-formly/schematics --ui-theme=ng-zorro- ...
- Redis的数据持久化
介绍 Redis 的数据持久化方案 Redis 的数据持久化主要有两大机制,AOF 日志和 RDB 快照. AOF 持久化是通过保存 Redis 服务器所执行的写命令来记录数据库状态. RDB 持久化 ...