躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介: 早春二月,研发倍忙,杂花生树,群鸥竟飞。为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让2023年的第一个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)搜索刘悦的技术博客查阅,欢迎诸君品鉴。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
16天前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
50 2
|
19天前
|
数据采集 机器学习/深度学习 人工智能
Python编程入门:从基础到实战
【10月更文挑战第36天】本文将带你走进Python的世界,从基础语法出发,逐步深入到实际项目应用。我们将一起探索Python的简洁与强大,通过实例学习如何运用Python解决问题。无论你是编程新手还是希望扩展技能的老手,这篇文章都将为你提供有价值的指导和灵感。让我们一起开启Python编程之旅,用代码书写想法,创造可能。
|
20天前
|
存储 SQL 数据库
深入浅出后端开发之数据库优化实战
【10月更文挑战第35天】在软件开发的世界里,数据库性能直接关系到应用的响应速度和用户体验。本文将带你了解如何通过合理的索引设计、查询优化以及恰当的数据存储策略来提升数据库性能。我们将一起探索这些技巧背后的原理,并通过实际案例感受优化带来的显著效果。
36 4
|
21天前
|
数据库 Python
异步编程不再难!Python asyncio库实战,让你的代码流畅如丝!
在编程中,随着应用复杂度的提升,对并发和异步处理的需求日益增长。Python的asyncio库通过async和await关键字,简化了异步编程,使其变得流畅高效。本文将通过实战示例,介绍异步编程的基本概念、如何使用asyncio编写异步代码以及处理多个异步任务的方法,帮助你掌握异步编程技巧,提高代码性能。
53 4
|
20天前
|
机器学习/深度学习 数据可视化 数据处理
Python数据科学:从基础到实战
Python数据科学:从基础到实战
26 1
|
21天前
|
机器学习/深度学习 JSON API
Python编程实战:构建一个简单的天气预报应用
Python编程实战:构建一个简单的天气预报应用
35 1
|
16天前
|
数据采集 存储 数据处理
探索Python中的异步编程:从基础到实战
【10月更文挑战第39天】在编程世界中,时间就是效率的代名词。Python的异步编程特性,如同给程序穿上了一双翅膀,让它们在执行任务时飞得更高、更快。本文将带你领略Python异步编程的魅力,从理解其背后的原理到掌握实际应用的技巧,我们不仅会讨论理论基础,还会通过实际代码示例,展示如何利用这些知识来提升你的程序性能。准备好让你的Python代码“起飞”了吗?让我们开始这场异步编程的旅程!
31 0
|
20天前
|
并行计算 数据挖掘 大数据
Python数据分析实战:利用Pandas处理大数据集
Python数据分析实战:利用Pandas处理大数据集
|
9天前
|
Web App开发 JavaScript 前端开发
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念,包括事件驱动、单线程模型和模块系统;探讨其安装配置、核心模块使用、实战应用如搭建 Web 服务器、文件操作及实时通信;分析项目结构与开发流程,讨论其优势与挑战,并通过案例展示 Node.js 在实际项目中的应用,旨在帮助开发者更好地掌握这一强大工具。
30 1
|
4天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####