Python面试题

1.列出5个常用python标准库

(1)os:提供与操作系统相关联的函数

(2)re:正则匹配

(3)sys:通常用于命令行参数

(4)math:数学运算

(5)datatime:处理日期时间

2.简述with方法打开文件帮我们做了什么?

with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的‘清理’操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等

with语句即’上下文管理器‘,在程序中用来表示代码执行过程中所处的前后环境,含有__enter__和__exit__方法的对象就是上下文管理器

__enter__():在执行语句之前,首先执行该方法,通常返回一个实例对象,如果with语句有as目标,则将对象赋值给as目标

__exit__():执行语句结束后,自动调用该方法,用户释放资源,若此方法返回布尔值True,程序会忽略异常

使用环境:文件读写、线程锁的自动释放等

3.列出python中可变数据类型和不可变数据类型,为什么?

不可变数据类型:数值型、字符串型和元组

不允许变量的值发生改变,如果改变了变量的值,相当于新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象(一个地址),用id()方法可以打印对象的id(id方法的返回值就是对象的内存地址)

可变数据类型:列表和字典、集合

允许变量的值发生变化,即如果对变量进行append、+=等操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象。即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象

4.Python 和其他语言的区别

Python是一门语言简洁优美,功能强大,应用领域广泛,具有强大完备的第三方库的一门弱类型的可移植、可扩展、可嵌入的解释型编程语言

与java相比:python比java要简单。python是函数为一等公民的语言,而java是类为一等公民的语言。python是弱类型语言,而java是强类型语言

与c相比:

对于使用:python的类库齐全并且使用简洁,很少代码实现的功能用c可能要很复杂

对于速度:python的运行速度相较于c绝对是很慢了。python和CPython解释器都是c语言编写的

5.Python 的解释器种类以及相关特点?

CPython:c语言开发的,使用最广的解释器

IPython:基于cpython之上的一个交互式计时器,交互方式增强,功能和cpython一样

PyPy:目标是执行效率,采用JIT技术,对python代码进行动态编译,提高执行效率

JPython:运行在java上的解释器,直接把python代码编译成java字节码执行

IronPython:运行在微软.NET平台上的解释器,把python编译成.NET的字节码

6.Python3 和 Python2 之间的区别?

(1)python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')
         python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,如 print 'hi'
(2)python2 range(1,10)返回列表,python3中返回迭代器,节约内存
(3)python2中使用ascii编码,python3中使用utf-8编码
(4)python2中unicode表示字符串序列,str表示字节序列
         python3中str表示字符串序列,byte表示字节序列
(5)python2中为正常显示中文,引入coding声明,python3中不需要
(6)python2中是raw_input()函数,python3中是input()函数

7.给定两个list,A和B,找出相同元素和不同元素

A、B中相同元素:print(set(A)&set(B))

A、B中不同元素:print(set(A)^set(B))

8.合并列表[1,5,7,9]和[2,2,6,8]

(1)a=[1,5,7,9]     b=[2,2,6,8]       a+b

(2)a.extend(b)       print(a)

9.如何打乱一个列表的元素?

random.shuffle(a)

10.字典操作中del和pop有什么区别?

del可以删除指定key的键值对,没有返回值。pop是从字典中取走指定key的键值对,并且返回键值

11.合并下面两个字典a={“A”:1,”B”:2},b={“C”:3,”D”:4}

方法(1)a.update(b)  print(a)

       (2)字典的dict(d1, **d2)方法和(**d1,**d2)方法  eg:print({**a,**b})

12.在读文件操作的时候会使用read、readline或者readlines,简述它们各自的作用

read()每次读取整个文件,它通常用于将文件内容放到一个字符串变量中

readline()一行一行的输出,该方法会把文件的内容加载到内存,所以对于大文件的读取操作来说非常的消耗内存资源,此时就可以通过readlines方法,将文件的句柄生成一个生产器,然后去读就可以了

13.说一说 Redis 的基本类型。

Redis支持五种数据类型:string(字符串)、hash、list、set、zset(有序集合)

14.请写一段 Python连接 Redis 数据库的代码。

import redis #创建连接池

pool = redis.ConnectionPool(host=’localhost’, port=6379, password=’a’,db=0)

r = redis.Redis(connection_pool = pool) #获取连接对象

r.flushdb() #清空数据库

r.set(‘name’,’value’) #设置一个键值

r.get(‘name’)

15.请写一段 Python 连接 MySQL 数据库的代码。

import pymysql

db = pymysql.connect(host=‘localhost’,port=3306,user=’root’,passwd=

’1234’,db=’user’,charset=’utf8’) #打开数据库连接

cursor = db.cursor() #获取操作游标

cursor.execute(‘sql语句’) #使用execute方法执行sql语句

data = cursor.fetchone() #获取一条数据

db.close()

16.了解 Redis 的事务么?

事务提供了一种‘将多个命令打包,一次性提交并按顺序执行’的机制,提交后在事务执行中不会中断。只有在执行完所有命令后才会继续执行来自其他客户的消息

Redis通过multi,exec,discard,watch实现事务功能

Multi:开始事务

Exec:提交事务并执行

Discard:取消事务

Watch:事务开始之前监视任意数量的键

Unwatch:取消watch命令对所有key的监控,所有监控锁将会被取消

关于事务管理:

(1)单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断

(2)没有隔离级别的概念:队列中的命令在事务没有被提交之前不会被实际执行

(3)不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制

17.了解分布式锁么?

分布式锁是控制分布式系统之间的同步访问共享资源的一种方式。对于分布式锁的目标,我们必须首先明确三点:(1)任何一个时间点必须只能有一个客户端拥有锁(2)不能有死锁,也就是最终客户端都能够获得锁,尽管可能会经历失败(3)错误容忍性要好,只要有大部分的redis实例存活,客户端就应该能够获得锁

分布式锁的条件:(1)互斥性:分布式锁需要保证在不同节点的不同线程的互斥(2)可重入性:同一个节点上的同一个线程如果获取了锁之后,能够再次获取这个锁(3)锁超时:支持超时释放锁,防止死锁(4)高效、高可用:加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级(5)支持阻塞和非阻塞:可以实现超时获取失败,tryLock支持公平锁和非公平锁

分布式锁实现方案(1)数据库实现(乐观锁)(2)基于zookeeper的实现(3)基于redis的实现

18.函数装饰器有什么作用?请列举说明?

Python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器返回值也是一个函数对象(函数的指针)

应用场景:(1)引入日志(2)函数执行时间统计(3)执行函数前预备处理(4)执行函数后清理功能(5)权限校验等场景(6)缓存(7)事务处理

19.@classmethod 和@staticmethod 用法和区别

@classmathod:是类方法,访问和修改类属性,进行类相关的操作,通过类或实例对象调用,需要传递cls类对象为参数

@staticmethod:静态方法,不访问类属性和实例属性,通过类或实例调用,相当于一个普通函数

20.Python 中的反射了解么?

计算机中的反射是在运行的时候来自我检查,并对内部成员进行操作。就是说这个变量的类型可以动态的改变,在运行的时候确定它的作用

在python中能够通过一个对象,找出其type、class、attribute或method的能力,称为反射或自省。具有反射能力的函数有type(),isinstance(),callable().dir().getattr()等

21.hasattr() getattr() setattr()的用法

这三种方法用于为对象属性的存在判断、获取和添加修改,简言之就是对象属性的‘增改查’

hasattr(object,name):判断对象是否存在name属性

getattr(object,name[,default]):获取object对象name属性的值,若没有name属性,则返回default值

setattr(object,name,value):给object对象的name属性赋值value,如果对象原本存在给定的属性name,则setattr会更改属性的值为给定的value,如果不存在属性name,会在对象中创建属性并赋值value

22.请列举你知道的 Python 的魔法方法及用途。

__new__用来创建类并返回这个类的实例

__init__将传入的参数来初始化该实例,以及初始化实例属性,与__new__共同构成了‘构造函数’

__del__将实例化后的对象销毁,即为析构函数

类调用:__call__允许一个类像函数一样被调用

属性访问:__getattr__访问对象不存在的属性时,调用该方法,用于定义访问行为

                  __setattr__设置对象属性时调用

                  __delattr__删除对象属性时调用

上下文管理器:__enter__():在执行语句之前,首先执行该方法,通常返回一个实例对象,如果with语句有as目标,则将对象赋值给as目标

                         __exit__():执行语句结束后,自动调用该方法,用户释放资源,若此方法返回布尔值True,程序会忽略异常

迭代器方法:__iter__:返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用时,以及当使用for x in container:方法循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法

                      __next__:返回迭代器的下一个元素

23.Python 的传参是传值还是传址?

Python对可变对象(字典或列表)传址,对不可变对象(数字、字符或元组)传值

24.在 Python 中是如何管理内存的?

Python内存池:内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率

Python中的内存管理机制--pymalloc python中的内存管理机制都有两套实现,一套是针对小对象,就是大小小于256bits时,pymalloc会在内存池中申请内存空间;当大于256bits,则会直接执行new/malloc的行为来申请内存空间

25.当退出 Python 时是否释放所有内存分配?

循环引用其它对象或引用自全局命名空间的对象的模块,在python退出时并非完全释放

26.正则表达式匹配中(.*)和(.*?)匹配区别?

(.*)是贪婪匹配,会把满足正则的尽可能多的往后匹配

(.*?)是非贪婪匹配,会把满足正则的尽可能少匹配

27.解释一下 python 中 pass 语句的作用?

Python中pass是空语句,是为了保持程序结构的完整性;pass不做任何事情,一般用做占位语句;一般在搭建程序框架的时候或在判断语句中使用

28.python 中的 is 和==

Is是身份运算符,判断两个对象的内存id是否相等

==是比较运算符,判断两个对象的值是否相等

进行值比较时使用==,判断是否是同一对象时使用is

29.Python 中的作用域

L(Local)局部做用域

E(Enclosing)闭包函数外的函数中

G(Global)全局作用域

B(Built-in)内建作用域

以L->E->G->B的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找

30.copy 和 deepcopy 的区别是什么?

Copy仅拷贝对象本身,而不拷贝对象中应用的其他对象

Deepcopy除拷贝对象本身,而且拷贝对象中引用的其他对象

Copy不会为子对象额外创建新的内存空间,而子对象被修改之后,这个子对象的引用都会发生改变;deepcopy是一个新对象的创建,只是用了和被拷贝对象相同的值,子对象改变不会影响被拷贝对象

31.代码中经常遇到的*args, **kwargs 含义及用法。

Args是arguments的缩写,表示位置参数

Kwargs是keyword arguments的缩写,表示关键字参数

32.w、a+、wb 文件写入模式的区别

r:读取文件,若文件不存在则会报错

w:写入文件,若文件不存在则会先创建再写入,会覆盖原文件

a:写入文件,若文件不存在则会先创建再写入,但不会覆盖原文件,而是追加在文件末尾

rb,wb:分别于r,w类似,用于读写二进制文件

r+:可读、可写,文件不存在也会报错,写操作时会覆盖

w+:可读、可写,文件不存在先创建,会覆盖

a+:可读、可写,文件不存在先创建,不会覆盖,追加在末尾

33.已知:AList = [1,2,3] BSet = {1,2,3}

(1) 从 AList 和 BSet 中 查找 4,最坏时间复杂度那个大?
(2) 从 AList 和 BSet 中 插入 4,最坏时间复杂度那个大?

Python的列表内部实现是数组(具体实现要看解析器,CPython的实现),因此就有数组的特点。超过容量会增加更多的容量,set,get是O(1),但del,insert,in的性能是O(n).

关于字典需要了解的是hash函数和哈希桶。一个好的hash函数使到哈希桶中的值只有一个,若多个key hash到了同一个哈希桶中,称之为哈希冲突。查找值时,会先定位到哈希桶中,再遍历hash桶。在hash基本没有冲突的情况下get,set,delete,in方面都是O(1)。

集合内部实现是dict的。在in操作上是O(1),这点比list要强

由此可见:(1)查找操作set优于list;(2)插入操作两个相同

34.TCP 和 UDP 的区别?

1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);

3.UDP程序结构较简单;
4.流模式与数据报模式 ;

5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证

35.简要介绍三次握手和四次挥手

(1)第一次握手:客户端发送SYN包(SYN=j)到服务器,并进入SYN_SEND状态,等待服务器确认

(2)第二次握手:服务器收到SYN包,必须确认客户的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。

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

完成三次握手,客户端与服务器开始传送数据

由于TCP连接是全双工的,连接的拆除需要发送四个包,因此称为“四次挥手”。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

(1)第一次挥手:客户端发送一个FIN,用来关闭客户到服务器的数据传送。 

(2)第二次挥手:服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。

(3)第三次挥手:服务器关闭与客户端的连接,发送一个FIN给客户端。 

(4)第四次挥手:客户端发回ACK报文确认,并将确认序号设置为收到序号加1

36.什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

概念:粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾

出现粘包的原因:出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成

发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据

接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据

粘包的处理方式:(1)当时短连接的情况下,不用考虑粘包的情况(2)如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象? 并发 概念:粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾 出现粘包的原因:出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成 发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据 接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据 粘包的处理方式:(1)当时短连接的情况下,不用考虑粘包的情况(2)如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包(3)如果双方建立长连接,需要在连接后一段时间内发送不同结构数据 接收方创建预处理线程,对接收到的数据包进行预处理,将粘连的包分开; 分包是指在出现粘包的时候我们的接收方要进行分包处理。(在长连接中都会出现) 数据包的边界发生错位,导致读出错误的数据分包,进而曲解原始数据含义。 粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包管接收存储就ok,也不用考虑粘包(3)如果双方建立长连接,需要在连接后一段时间内发送不同结构数据

接收方创建预处理线程,对接收到的数据包进行预处理,将粘连的包分开;

分包是指在出现粘包的时候我们的接收方要进行分包处理。(在长连接中都会出现) 数据包的边界发生错位,导致读出错误的数据分包,进而曲解原始数据含义。

粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包

37.简述 GIL

GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。

多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大

38.IO 多路复用的作用?

I/O多路复用实际上就是用select, poll, epoll监听多个io对象,当io对象有变化(有数据)的时候就通知用户进程。好处就是单个进程可以处理多个socket

39.select、poll、epoll 模型的区别?

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作

(1)select==>时间复杂度O(n)

它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。

select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:

1、 单个进程可监视的fd数量被限制,即能监听端口的大小有限。

      一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.

2、 对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:

       当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。

3、需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大

(2)poll==>时间复杂度O(n)

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

但是它没有最大连接数的限制,原因是它是基于链表来存储的.但是同样有一个缺点:

1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。                   

2、poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

(3)epoll==>时间复杂度O(1)

epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))

epoll有EPOLLLT和EPOLLET两种触发模式,LT是默认的模式,ET是“高速”模式。LT模式下,只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作,而在ET(边缘触发)模式中,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无 论fd中是否还有数据可读。所以在ET模式下,read一个fd的时候一定要把它的buffer读光,也就是说一直读到read的返回值小于请求值,或者 遇到EAGAIN错误。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

epoll为什么要有EPOLLET触发模式?

如果采用EPOLLLT模式的话,系统中一旦有大量你不需要读写的就绪文件描述符,它们每次调用epoll_wait都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率.。而采用EPOLLET这种边沿触发模式的话,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符

epoll的优点:

1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。

3、 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销

总结:

1、支持一个进程所能打开的最大连接数

Select:单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。

Poll:poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的

Epoll:虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器能打开20万左右的连接

2、FD剧增后带来的IO效率问题

Select:因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。

Poll:同上

Epoll:因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。

3、 消息传递方式

Select:内核需要将消息传递到用户空间,都需要内核拷贝动作

Poll:同上

Epoll:epoll通过内核和用户空间共享一块内存来实现的。

40.什么是并发和并行?

并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。

并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

并行在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在,并发能够在单处理器系统中存在是因为并发是并行的假象,并行要求程序能够同时执行多个操作,而并发只是要求程序假装同时执行多个操作(每个小时间片执行一个操作,多个操作快速切换执行)。

当有多个线程在操作时,如果系统只有一个 CPU,则它根本不可能真正同时进行一个以上的线程,它只能把 CPU 运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状态.这种方式我们称之为并发(Concurrent)。

当系统有一个以上 CPU 时,则线程的操作有可能非并发。当一个 CPU 执行一个线程时,另一个 CPU 可以执行另一个线程,两个线程互不抢占 CPU 资源,可以同时进行,这种方式我们称之为并行(Parallel)

41.解释什么是异步非阻塞?

 同步异步是针对调用者来说的,调用者发起一个请求后,一直干等被调用者的反馈就是同步,不必等去做别的事就是异步。

 阻塞非阻塞是针对被调用者来说的,被调用者收到一个请求后,做完请求任务后才给出反馈就是阻塞,收到请求直接给出反馈再去做任务就是非阻塞。

42.threading.local 的作用?

threading.local()这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,如果你在开发多线程应用的时候 需要每个线程保存一个单独的数据供当前线程操作,可以考虑使用这个方法,简单有效。举例:每个子线程使用全局对象a,但每个线程定义的属性a.xx是该线程独有的,Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。

43.git 如何查看某次提交修改的内容

1、首先,需要通过git log打印所有commit记录

2、找到你想查看的那次commit的commitid。

3、查看修改。git show commitId

4、看某次commit中具体某个文件的修改:git show commitId fileName

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值