记录第一次面试


面试,django,python,数据

看标题应该就知道了,这是我第一次面试,在这里记录一下。

面试,django,python,数据

先来看一下简历(小菜鸡一个,大佬轻喷):

面试官:先来一个简单的自我介绍吧。

Alex:好的,面试官你好,我叫Alex,今年十九岁,目前就读于中华大学,所学专业是人工智能与大数据。
在校期间对于专业课方面非常重视,有扎实的编程基础,拿过两次校级奖学金,大一就了获得蓝桥杯A组二等奖,带队参加过很多比赛,像大学生创新创业、华北五省等等,也拿过很多奖项。
技术能力方面,对Python比较熟悉,经常使用Django框架,C++和Go有一些了解,C++是学校的必修课,Go是我自学的。另外对于前端相关的技术,比如JavaScript、jQuery、BootStrap、Vue都有些了解,还自学过Linux操作系统,熟悉一些基本的操作和Vim指令,数据库方面经常用的是MySQL和Redis。
另外再大学期间还加入了一个社团,Matrix工作室,因为成员比较多,不方便管理,各种工作流程都不是很规范,我就开发了一套工作室官网和管理系统,用到的技术有Django、jQuery、BootStrap、RBAC组件等等,目前这两个项目已经初步做完了,因为我们还没开学,所以打算再继续优化,等开学返校之后再测试上线。
大一下学期开始在中华小学实习,担任机器人社团指导老师,主要是教三年级到六年级的孩子们一些基本的Python编程、玩树莓派机器人和展示一些AI方面的小玩具等等。
我个人是非常热爱编程,而且适应能力强,单身可加班,996无压力,我想面试的岗位是Python实习生,以上就是我的自我介绍,请多多指教,谢谢。

面试常规操作,上来先自我介绍,这里我准备了两版,一个是40秒 ~ 一分钟快速版,另一个是一分半 ~ 两分钟版,面试官没有说具体的时间限制,就用了比较详细的版本。

面试官:你简历中写的这几个项目,觉得哪个是功能比较完善的呢?

Alex:我觉得比较完善的是工作室的官网和管理系统,因为这两个是真正要投入使用的,所以做得比较详细。这两个项目其实属于比较简单的类型,不用考虑高并发之类的问题,主要集中在博客系统、权限管理之类的功能实现上。

回答面试官的问题,然后在答案中提到高并发这个比较热的词,引导面试官朝这个方向问,当然提前要预备这方面的知识。

面试官:这两个项目大概有哪些功能?

Alex:工作室官网这个项目,首先第一个功能是针对新加入工作室的成员的培训,主要也是大一的同学,没有学习的途径和资源,每加入一批新成员我们就要安排几次培训,费时费力,所以我们一些学长学姐就把自己的学习历程总结整理到网站上,帮助新成员快速学习。第二个功能也是针对新成员的,我们以前纳新都是先宣讲,然后发纸质的报名表,这样效率非常低,因此我们制作了简历系统,想要加入工作室的学生可以直接投递简历。第三个功能是一个在线答题的平台,主要是用于对新成员的考核和平时的练习。第四个功能是一个博客系统,工作室的成员可以在这个平台上写博客,做笔记,同时引入了积分制度,写博客可以赚积分,积分主要用于做绩效考核和等级划分。
管理系统这个项目就是用于统计工作室所有成员的信息,学习情况,还有等级、部门 、团队的划分这些功能,通过RBAC组件可以对不同的成员赋予不同角色而拥有不同的权限。

面试官没有问我们引导的问题,随机应变嘛,问啥说啥,针对简历上项目的功能要提前准备好,同时通过一些专业术语继续引导面试官提问的方向。

面试官:你刚才说这两个项目都是你负责的,那你在项目中主要负责那一块呢?

Alex:我主要负责的是搭建项目整体的框架,实现一些主要的功能,前后端的框架都是我搭建的,但是并不完善,前端像页面的美化、特效,后端像登录、token验证这些功能交给专门做前后端的人去做,之后我就负责前后端的联调,像API、数据格式的定义这些工作。

面试官:在做项目的过程中有没有遇到什么困难?

Alex:在工作室官网这个项目的开发过程中并没有遇到什么太大的困难,都是一些很常见的功能,而在管理系统的项目开发过程中,一开始因为对Django声明周期不太熟悉,导致在开发Stark组件的时候有很多莫名其妙的错误,还不知道问题出在哪,后来我们还是积极查阅资料,读了很多大佬关于Stark组件的博客和源码,重新梳理了流程才得以解决。在线教育平台这个项目中遇到的问题就比较多了,比较麻烦的是跨域的问题,像工作室的官网和管理系统并不是前后端分离开发的,所以在解决跨域问题上没有什么经验,也是查了很多博客,最后在后端Django加了一个中间件,通过process_response添加允许的操作才得以解决。

关于项目的提问大概就到这,1.项目有哪些功能,2.项目开发过程中遇到了什么困难,都是怎么解决的,这些问题在往简历上写项目经历的时候就得准备好。

面试官:对Python的进程、线程、协程有哪些认识?

Alex:先说进程吧,我们写的代码并不能直接运行,只有将程序装载到内存中,操作系统为它分配资源才能运行,这种执行的程序就叫进程,进程是计算机最小的资源分配单位;而线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中实际工作的单位,一个进程可以并发多个线程,每条线程并行执行不同的任务,当然是在不考虑GIL锁的情况下;而协程一种基于单线程实现并发的手段,是由用户程序自己控制调度的,在单线程内开启协程,一旦遇到IO操作,就会从应用程序级别控制切换,以此来提升效率。

面试官:你刚刚提到了GIL锁,可以简单说一下么?

Alex:GIL,就是Global Interpreter Lock,中文名叫全局解释器锁,这是一个互斥锁,用来防止多个本机线程同时执行Python字节码。GIL只存在于CPython中,存在即合理,CPython的内存管理不是线程安全的,所以GIL锁也是必要的。每次执行Python程序,都会产生一个独立的进程,在这个进程中,不仅有该进程开启的线程,还有解释器开启的线程,比如垃圾回收这种解释器级别的线程。所有的线程运行在一个进程内,线程的任务需要将代码传给解释器去执行,而数据都是共享的,这样就到导致线程不安全。举个简单的例子:对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理。所以GIL可以保证Python解释器同一时间只能执行一个线程。

终于按照引导的内容提问了,开始背答案。

面试官:然后你说一下什么是装饰器、生成器和迭代器。

Alex:首先说一下迭代器吧,迭代器对象就是实现了iter() 和 next()方法的对象,其中iter()返回迭代器本身,而next()返回容器的下一个元素,在结尾处引发StopInteration异常。而生成器是创建迭代器的工具,在Python中,一边循环一边计算的机制,称为生成器(Generator)。生成器对延迟操作提供了支持,所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果。装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。装饰器就有很多应用场景了,比如可以在Web开发中用于检查某个用户是否有权限去做某件事,这种授权检测被大量使用在Django、Flask这种Web框架中。另外装饰器也可以用于打印日志,记录程序运行时间。

这部分其实不太熟,瞎编了好多,这是结合当时说的和事后查的资料总结的答案。

面试官:那你在项目中有没有用到刚才说的装饰器做登录认证的权限验证?

Alex:这个倒是没有用到,在工作室官网和管理系统中直接用的Django自带的权限验证组件,在线教育平台这个项目用的是Django Rest Framework的权限验证组件。

面试官:如果让你自己去写一个登录验证的功能,你会怎么去实现?

Alex:首先要获取前端发送过来的用户名和密码,然后去数据库中验证数据合法性,验证通过之后,给用户生成一个token,将用户的基本信息+token一方面存放到Redis中,另一方面返回个客户端。当用户再次请求的时候,必须携带token值,后端从数据包中获取token,然后在Redis中获取用户的基本信息并封装到request中。如果请求中没有token值的话说明用户未登录,或者token已经过期。这样,通过token和Redis可以实现用户的登录验证。

这部分面试官估计是觉得我装饰器掌握的不好,想问我怎么用装饰器来做一个登录验证的功能,结果我一通胡扯,还好没被打断,又详细的问了一遍。

面试官:那这个功能你打算用什么实现?装饰器还是什么?

Alex:我觉得这个功能属于比较简单的类型,不需要用到装饰器吧,写个函数就行了,实在想用装饰器也可以。

哈哈,装饰器实在忘记了,极力回避。

面试官:不用装饰器的话那这个功能你打算怎么实现?

Alex:其实可以写一个验证中间件,如果请求中携带了token的话,就按照之前说的那种方式做验证,没有的话就正常走。

脑袋灵光一下,想到了可以用中间件。

面试官:简述一下Django的生命周期。

面试,django,python,数据

这个我就不叙述了,直接贴图:

面试官:除了Django这个框架之外还有没有了解过其它的Python Web框架?

Alex:目前还没有,因为我自觉Django掌握的还不是很熟练,想要先把Django吃透,再去了解其它的框架,当然选择Django也是有原因的,首先就Django是最负盛名且最成熟的Web框架,而且拥有丰富的组件,可以自由扩展。其它的Web框架,比较熟悉Flask、Tornado的单词书写。

嘿嘿,开个小玩笑。

面试官:那假如说公司里有一个Tornado的项目让你接手,大概需要多少时间?

Alex:这个要看项目的复杂程度了,如果不是很深入的话,可以很快的入手。假如说像Matrix工作室的官网和管理系统这样比较简单的,大概需要半个月左右,但在线教育平台就比较复杂了,用到了一个扩展的第三方库,时间大概有一个月左右。

这个问题我没听全,问的是接手一个Tornado项目,我就听见了项目需要多少时间,哈哈,结果也是乱说一堆,面试的时候一定要把音量调大。

面试官:在前后端分离的项目中,交互经常用到RestFul规范,简述一下吧。

这我也不多说了,直接上答案:

  1. 面向资源编程
    每个URL代表一种资源,URL中尽量不要用动词,要用名词。
  2. 根据method不同,进行不同的操作
    GET/POST/PUT/DELETE/PATCH
  3. 在URL中体现版本
    https://www.bootcss.com/v1/mycss
  4. 在URL中体现是否是API
    https://www.bootcss.com/api/mycss
  5. 在URL中的过滤条件
    https://www.bootcss.com/v1/mycss?page=3
  6. 尽量使用HTTPS
    https://www.bootcss.com/v1/mycss
  7. 响应时设置状态码
      1* 信息,服务器收到请求,需要请求者继续执行操作
      2* 成功,操作被成功接收并处理
      3* 重定向,需要进一步的操作以完成请求
      4* 客户端错误,请求包含语法错误或无法完成请求
      5* 服务器错误,服务器在处理请求的过程中发生了错误
  8. 返回值
      GET请求 返回查到所有或单条数据
      POST请求 返回新增的数据
      PUT请求 返回更新数据
      PATCH请求 局部更新 返回更新整条数据
      DELETE请求 返回值为空
  9. 返回错误信息
    返回值携带错误信息
  10. Hypermedia API
    如果遇到需要跳转的情况 携带调转接口的URL

面试官:状态码403个404代表什么?

403:表明对请求资源的访问被服务器拒绝了
404:表明服务器上无法找到请求的资源

面试官:那502和503呢?

502(错误网关):服务器作为网关或代理,从上游服务器接收到无效响应
503(服务不可用):服务器目前无法使用(由于超载或停机维护)。

面试官:简述一下三次握手和四次挥手。

建立双工通信,确保双方都能收到对方的信息,所以需要3次握手。

面试,django,python,数据

第1次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入同步已发送状态,等待服务器确认;SYN:同步序列编号。

第2次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入同步已接受状态。

第3次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

全双工关闭需要客户端和服务器发送和接受都关闭,但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,只能先回复一个ACK报文,所以需要4次挥手

面试,django,python,数据


第1次挥手:客户端进程发出连接释放报文,并且停止发送数据。此时,客户端进入FIN-WAIT-1(终止等待1)状态。

第2次挥手:服务器收到连接释放报文,发出确认报文。服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第3次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

第4次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

面试官:说一下什么是TIME-WAIT和CLOSE-WAIT。

由于socket是全双工的工作模式,一个socket的关闭,是需要四次握手来完成的:

  1. 主动关闭连接的一方,调用close();协议层发送FIN包 ;
  2. 被动关闭的一方收到FIN包后,协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方等待被动关闭一方的应用程序,调用close操作 ;
  3. 被动关闭的一方在完成所有数据发送后,调用close()操作;此时,协议层发送FIN包给主动关闭的一方,等待对方的ACK,被动关闭的一方进入LAST_ACK状态;
  4. 主动关闭的一方收到FIN包,协议层回复ACK;此时,主动关闭连接的一方,进入TIME_WAIT状态;而被动关闭的一方,进入CLOSED状态 ;
  5. 等待2MSL时间,主动关闭的一方,结束TIME_WAIT,进入CLOSED状态 ;

接下来就是对一些工具的提问,像是Git、Nginx和Jenkins,也就是问问有没有用过。然后问了一下排序算法和自我评价。