1.线程、进程、协程
这个问题被问的概率相当之大,其实多线程,多进程,在实际开发中用到的很少,除非是那些对项目性能要求特别高的,有的开发工作几年了,也确实没用过,你可以这么回答,给他扯扯什么是进程,线程(cpython中是伪多线程)的概念就行,实在不行你就说你之前写过下载文件时,用过多线程技术,或者业余时间用过多线程写爬虫,提升效率。
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
线程: 调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
协程三种方式:
(1)使用yield 来实现协程
(2)使用greenlet 模块,通过switch来切换不同的代码块协程运行
(3)使用gevent 模块实现协程,打猴子补丁,遇到耗时操作自动切换
2.多线程解决资源竞争问题的方式(线程同步方式)
锁机制(Lock,RLock可重入锁)、信号量、condiction条件判断、同步队列、event对象
线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱 ,即所谓的线程不安全那么怎么解决多线程竞争问题?-- 锁。
锁的好处:
确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
锁的致命问题:死锁。
锁(Lock)是 Python 提供的对线程控制的对象。有互斥锁、可重入锁。
若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。GIL 锁(有时候,面试官不问,你自己要主动说,增加 b 格,尽量别一问一答的尬聊,不然最后等到的一句话就是:你还有什么想问的么?)
GIL 锁 全局解释器锁(只在 cpython 里才有)作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以 cpython 里的多线程其实是伪多线程!
所以Python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程,进程和线程的切换时由系统决定,而协程由我们程序员自己决定,而模块 gevent 下切换是遇到了耗时操作才会切换。
三者的关系:进程里有线程,线程里有协程。
3.进程之间怎么共享全局变量?
进程是系统进行资源分配的独立单位,在以前的python版本中,进程间的数据交互只能通过Queue、Pipes等方式来实现,数据无法直接共享。
在Python 3.8中,multiprocessing模块提供了SharedMemory类,可以在不同的Python进程之间创建共享的内存block。目前支持int、float、str、bytes、bool、None、numpy.ndarray等一部分Python对象。
当然,shared_memory在实际应用中肯定不会如此简单,
比如SharedMemory.ShareableList和SharedMemory.SharedMemory的使用本身有很多规则和限制、比如需要考虑数据锁的问题等等,但是共享内存确实为进程间通讯提供了一个新的解决方案,而且据说其通讯效率也是非常之高的。
4.线程与进程扩展
多进程适合在 CPU 密集型操作(cpu 操作指令比较多,如位数多的浮点运算)。
多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)。
线程是并发,进程是并行;
进程之间相互独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。
并行:同一时刻多个任务同时在运行。
并发:在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情况。
实现并行的库有:multiprocessing
实现并发的库有:threading
程序需要执行较多的读写、请求和回复任务的需要大量的 IO 操作,IO 密集型操作使用并发更好。
CPU 运算量大的程序程序,使用并行会更好。
IO 密集型:系统运作,大部分的状况是 CPU 在等 I/O (硬盘/内存)的读/写。
CPU 密集型:大部份时间用来做计算、逻辑判断等 CPU 动作的程序称之 CPU 密集型。
5.装饰器
装饰器本质上是一个 Python 函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景。比如:插入日志、性能测试、事务处理、缓存、权限的校验等场景有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
计算装饰器装饰所用时间
import time
start = time.time()
def timeit(f):
print('开始装饰啦')
for i in range(47000):
pass
return f
@timeit # foo=timeit(foo)
def foo():
pass
end = time.time()
s = end - start
print(s)
6.闭包
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
7.生成器、迭代器的区别?
迭代器是一个更抽象的概念,任何对象,如果它的类有 next 方法和 iter 方法返回自己本身,对于 string、list、dict、tuple 等这类容器对象,使用 for 循环遍历是很方便的。在后台 for 语句对容器对象调用 iter()函数,iter()是 python 的内置函数。iter()会返回一个定义了 next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是 python 的内置函数。在没有后续元素时,next()会抛出一个 StopIteration 异常。
生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用 yield 语句。每次 next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
区别:生成器能做到迭代器能做的所有事,而且因为自动创建了iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration 异常
8.http协议
浏览器访问服务器的过程
用户输入网址.
浏览器请求DNS服务器, 获取域名对应的IP地址.
请求连接该IP地址服务器.
发送资源请求. (HTTP协议)
web服务器接收到请求, 并解析请求, 判断用户意图.
获取用户想要的资源.
将资源返回给web服务器程序.
web服务器程序将资源数据通过网络发送给浏览器.
浏览器解析请求的数据并且完成网页数据的显示.
扩:
HTTP协议就是超文本传输协议(HyperText Transfer Protocol),通俗理解是浏览器和web服务器传输数据格式的协议,HTTP协议是一个应用层协议。
HTTP协议是基于TCP协议的,发送数据之前需要建立好连接
网络传输-TCP/IP四层模型
链路层(数据链路层/网络接口层):包括操作系统中的设备驱动程序、计算机中对应的网络接口卡.
网络层:处理分组在网络中的活动,比如分组的选路.
运输层:主要为两台主机上的应用提供端到端的通信.
应用层:负责处理特定的应用程序细节.
OSI开放系统互联(Open System Interconnection)的7层从上到下分别是
7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层
HTTP协议响应报文分为4部分,每部分之间使用\r\n进行分割
响应行
响应头
空行(\r\n)
响应体
现在http用的是长连接 1.长度 2.有个标识符
9.tcp与udp的区别
TCP:英文全拼(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议.
优点:
可靠,稳定
适合传输大量数据
缺点:
传输速度慢
占用系统资源高
TCP和UDP区别
TCP面向连接,有3次握手,4次挥手; UDP是不面向连接;
TCP提供可靠的数据传输,也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP不保证可靠的数据传输,容易出现丢包情况;
TCP需要连接传输速度慢,UDP不需要连接传输速度快
TCP不支持发广播;UDP支持发广播
TCP对系统资源要求较多,UDP对系统资源要求较少。
TCP适合发送大量数据,UDP适合发送少量数据
TCP有流量控制,UDP没有流量控制
浏览器、QQ文件传输用的是Tcp
扩
ip地址,协议,端口就可以标识网络的进程
现在http用的是长连接 1.长度 2.有个标识符
请简单说一下tcp三次握手和四次挥手?
三次握手过程:
1 首先客户端向服务端发送一个带有 SYN 标志,以及随机生成的序号 100(0 字节)的报文
2 服务端收到报文后返回一个报文(SYN200(0 字节),ACk1001(字节+1))给客户端
3 客户端再次发送带有 ACk 标志 201(字节+)序号的报文给服务端
至此三次握手过程结束,客户端开始向服务端发送数据。
1 客户端向服务端发起请求:我想给你通信,你准备好了么?
2 服务端收到请求后回应客户端:I’ok,你准备好了么
3 客户端礼貌的再次回一下客户端:准备就绪,咱们开始通信吧!
整个过程跟打电话的过程一模一样:1 喂,你在吗 2 在,我说的你听得到不 3 恩,听得到(接下来请开始你的表演)
补充:SYN:请求询问,ACk:回复,回应。
四次挥手过程:
由于 TCP 连接是可以双向通信的(全双工),因此每个方向都必须单独进行关闭(这句话才是精辟,后面四个挥手过程都是其具体实现的语言描述)
四次挥手过程,客户端和服务端都可以先开始断开连接
1 客户端发送带有 fin 标识的报文给服务端,请求通信关闭
2 服务端收到信息后,回复 ACK 答应关闭客户端通信(连接)请求
3 服务端发送带有 fin 标识的报文给客户端,也请求关闭通信
4 客户端回应 ack 给服务端,答应关闭服务端的通信(连接)请求
1.客户端向服务端发起关闭连接:我要睡觉了了,88哟
2.服务端收到消息后回复:好的
3.服务端再次发送请求:我也88哟
4.客户端收到后回复:嗯嗯,88吧
服务端收到消息后开始睡觉,客户端等待几秒,也开始睡觉。
补:SYN: 表示连接请求 ACK: 表示确认
FIN: 表示关闭连接 seq:表示报文序号 ack: 表示确认序号
10.socket
socket(简称 套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的
例如我们每天浏览网页、QQ 聊天、收发 email 等等
11.ython3编码转换
str->bytes:encode编码
bytes->str:decode解码
dumps与loads 项目接口里用到
dumps:将dict(字典)转换为str(字符串)。
loads:用于将str(字符串)转换为dict(字典)
12.seo搜索优化
SEO(Search Engine Optimization):汉译为搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。很大程度上是网站经营者的一种商业行为,将自己或自己公司的排名前移。
搜索引擎优化的技术手段主要有黑帽(black hat)、白帽(white hat)两大类。通过作弊手法欺骗搜索引擎和访问者,最终将遭到搜索引擎惩罚的手段被称为黑帽,比如隐藏关键字、制造大量的meta字、alt标签等。而通过正规技术和方式,且被搜索引擎所接受的SEO技术,称为白帽。
13.***args kwargs
*args 可变参数 用来将参数打包成tuple(元组)给函数体调用 接收多余的位置参数
**kwargs 字典参数 打包关键字参数成dict(字典)给函数体调用 接收多余的关键字参数
注意点:推荐书写顺序
def 函数名(位置a,可变参数*args,默认参数b=2,字典参数**kwargs):
pass
函数名(位置0,数据1,数据2,数据3,…,关键字参数b=3,关键字参数c=4,关键字参数d=5)
14.linux命令
cd ls touch mkdir cat tree more clear pwd cd (cp 路径/文件名 路径: 把原指定路径的文件拷贝到新指定路径) rm mv
lsof -i : 端口号 查看端口号占用
kiss -9 杀死占用端口的进程
ps aux|grep ngnix 查看nginx服务器里运行的程序
15.http与https的区别
http以及https的概念和区别
HTTPS比HTTP更安全,但是性能更低
HTTP:超文本传输协议,默认端口号是80
超文本:是指超过文本,不仅限于文本;还包括图片、音频、视频等文件
传输协议:是指使用共用约定的固定格式来传递转换成字符串的超文本内容
HTTPS:HTTP + SSL(安全套接字层),即带有安全套接字层的超本文传输协,默认端口号:443
SSL对传输的内容(超文本,也就是请求体或响应体)进行加密
16.斐波那契数列
数列中第一个数为0,第二个数为1,其后的每一个数都可由前两个数相加得到:
0,1,1,2,3,5,8,13,21…
求斐波契那数列第1000项的值
a=0
b=1
for i in range(1000):
a,b=b,a+b
print(b)
17.实现一个线程安全的单例模式
def Singleton(cls):
instances = {}
def get_instance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return get_instance
扩展
单例模式:
1.概念:只能创建一个对象
2.代码核心思想:限制函数或者方法 内部的 某部分 的 执行次数
限制代码的执行:
1.定义标记,判断标记
2.第一个调用者使用之后,修改标记
3.关键点:在哪儿定义标记 最重要(所有调用者共享的数据)
单例模式的应用场景:
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。 1.网站的计数器 2.应用配置 3.多线程池 4.数据库配置,数据库连接池 5.应用程序的日志应用…
18.常见的响应状态码
200:成功
302:跳转,新的url在响应的Location头中给出
303:浏览器对于POST的响应进行重定向至新的url
307:浏览器对于GET的响应重定向至新的url
403:资源不可用;服务器理解客户的请求,但拒绝处理它(没有权限)
404:找不到该页面
500:服务器内部错误
503:服务器由于维护或者负载过重未能应答,在响应中可能可能会携带Retry-After响应头;有可能是因为爬虫频繁访问url,使服务器忽视爬虫的请求,最终返回503响应状态码
19.开放题马与赛道问题
1.25匹马,5条跑道,比赛时不计算时间只计算排名,要选出跑的最快的前3名至少需要几场比赛
7场,
5场比赛定出每组最快的马
1场比赛定出每组的名次,本场比赛可定出第一名以及淘汰两组马
分别用第一名的组的2,3名和第2名的组的1,2名和第3名组的1名进行1场比赛,定出2,3名
至此比赛完毕
20.python的内存管理机制
Python的内存管理机制:引入计数、垃圾回收(引用计数、标记清除、分代回收)、内存池机制
(Python 内部默认的小块内存与大块内存的分界点定在 256 个字节,当申请的内存小于 256 字节时,PyObject_Malloc会在内存池中申请内存;当申请的内存大于 256 字节时,PyObject_Malloc 的行为将蜕化为 malloc 的行为。)
引用计数:
引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。
21.内存泄露是什么?如何避免?
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。
有 del() 函数的对象间的循环引用是导致内存泄漏的主凶。
不使用一个对象时使用:del object 来删除一个对象的引用计数就可以有效防止内存泄漏问题。
通过 Python 扩展模块 gc 来查看不能回收的对象的详细信息。
可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否为 0 来判断是否内存泄漏。
22. Python 中 pass 语句的作用是什么?
在编写代码时只写框架思路,具体实现还未编写就可以用 pass 进行占位,使程序不报错,不会进行任何操作。
23.cookie 和 session 的区别?
1、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
2、cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗考虑到安全应当使用 session。
3、session 会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能考虑到减轻服务器性能方面,应当使用 cookie。
4、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
5、建议: 将登陆信息等重要信息存放为 SESSION 其他信息如果需要保留,可以放在 cookie 中