常见概念 1.简述解释型和编译型语言及其优缺点 2.变量名的命名规范 3.简述break和continue,并说出两者之间的相同之处 4.is 和 == 的区别 5.简述位和字节的关系 6.pass和type,id的作用 7.列举布尔值False的常见值 8.简述赋值/深拷贝/浅拷贝 9.驻留机制中数字和字符串的规则 10.简单描述一下递归 11.函数名的应用 12.什么是函数,优点是什么? 13.return的作用 14.函数的参数 15.形参角度的第四种传参方式: 仅限关键字参数 16.*args和*kwargs的作用 17.在函数以外的使用 返回的都是列表,位置任意 18.描述一下命名空间分类及加载顺序和取值顺序 19.global / nonlocal / globals / locals 20.什么是闭包 21.列举你曾经使用过的标准库模块 22.列举你曾经使用过的第三方模块 23.序列化模块在工作中用在哪个环节 24.请说出sys.path.append()的作用 25.实例化

编译型:计算机运行前将程序全部编译后才运行的语言,运行速度快,开发效率低

解释型:计算机通过虚拟机边编译边运行的语言,云行速度慢,开发效率高

2.变量名的命名规范

1.由字母,数字,下划线组成
2.禁止以数字开头
3.禁止使用python中的关键字及内置函数的名字
4.不建议使用中文和拼音
5.具有可描述性
6.区分的大小写
7.推荐写法:驼峰体: AgeOfOldboy = 56 下划线:age_of_oldboy = 56
8.不建议太长

3.简述break和continue,并说出两者之间的相同之处

break:跳出当前循环
continue:伪装成循环体中的最后一行代码,跳出当前循环,进行下次循环
相同点:他们以下的的代码都不执行

4.is 和 == 的区别

is 是判断两边的内存地址是否相同
== 是判断两边的值(内容)是否相同

5.简述位和字节的关系

1字节等于8位

6.pass和type,id的作用

pass 站位,为了保持程序结构的完整性
type 是判断数据类型(获取对象从属于的类)
id 是判断内存地址

7.列举布尔值False的常见值

数字:0  字符串:""  列表:[]  字典:{}  集合:set()  元组:()  布尔值:False
其他:None   (3<2)

8.简述赋值/深拷贝/浅拷贝

赋值:多个变量名指向同一个内存地址,一个变量对其操作,其他变量查看时都变动
浅拷贝:只拷贝第一层空间,即开辟新的内存地址,不可变数据和可变数据共用
深拷贝:开辟一块新的内存空间,不可变数据共用,可比那数据重新开辟空间

9.驻留机制中数字和字符串的规则

小数据支持:
字符串:纯字母和数字的时候长度任意,内存地址相同。
Python36纯字母和数字乘法总长度 <= 20 内存地址相同。
Python37纯字母和数字乘法总长度 <= 4096 内存地址相同。
中文和特殊符号乘法的时候只能乘以 0 内存地址相同
数字:-5 ~ 256 
布尔值:True False

代码块支持:
字符串:◦定义字符串的时候内容,长度任意内存地址相同。
字符串进行乘法的时候总长度 <=20 内存地址相同。
中文,特殊符号 乘法的时候只能乘以1或 0
数字:相同的数字内存地址相同
布尔值:相同的内存地址相同

10.简单描述一下递归

1.不断地调用自己本身
2.有明确的终止条件

11.函数名的应用

1.可以当做值被赋值给变量
2.当做元素存放在容器中
3.当作函数的参数
4.当作函数的返回值

12.什么是函数,优点是什么?

定义:以功能为导向,一个函数封装一个功能
1.减少重复代码
2.提高代码的可读性

13.return的作用

    return 返回值
    return 返回一个内容(就是内容本身) 可以返回任意类型
    return 返回多个内容,以元组的形式返回
    return 终止函数 ,切记不能终止循环
    return 下方的代码不执行
    return 不写返回值或者没有return就返回None
    return 将内容返回给了函数的调用者

14.函数的参数

形参:函数定义时的参数,位置参数>默认参数>混合参数
实参:函数调用时的参数,位置参数>关键字参数>混合参数
传参:将实参传给形参的过程

15.形参角度的第四种传参方式: 仅限关键字参数

def func(a,*args,sex='男',c, **kwargs):
    print(a)
    print(args)
    print(sex)
    print(c)
    print(kwargs)
func(1,c=4,name='alex') #c就是仅限关键字参数

16.*args和*kwargs的作用

*args 动态位置参数,可以接受0个或多个位置参数,返回元组,不传值时()
*kwaargs 动态关键字参数,可以接受0个或多个关键字参数,返回字典,不传值时{}

17.在函数以外的使用 返回的都是列表,位置任意

a,*b,c = [1,2,3,4,5,6]
print(a,b,c) #1 [2, 3, 4, 5] 6

a,*b,c = [1,6]
print(a,b,c) #1 [] 6

a, *b = range(1,7)
print(a,b) #1 [2, 3, 4, 5, 6]

a, *b = (1,2,3,4)
print(a,b) #1 [2, 3, 4]

18.描述一下命名空间分类及加载顺序和取值顺序

内置命名空间:存储的是内置函数与模块等
全局命名空间:当前py文件,存放的是变量与值的对应关系
局部命名空间:函数运行时,在内存中开辟一个临时的名称空间,存放的是函数内部的变量与值的对应关系,函数结束后就消失
加载顺序:内置命名空间 > 全局名称空间 > 局部命名空间   
取值顺序:局部命名空间 > 全局命名空间 > 内置命名空间
全局作用域:内置命名空间 + 全局命名空间
局部作用域:局部命名空间

19.global / nonlocal / globals / locals

locals() 返回是当前局部变量的深拷贝,修改locals() 中变量值的时候,实际上对于原变量本身是没有任何影响的,(全局中和globals()用法相同)
而globals()返回的是全局变量的字典,修改其中的内容,值会真正的发生改变
global:在函数内部修改全局空间的变量对应的值;声明一个全局变量
nonlocal:在嵌套函数中,修改局部空间的变量值,只修改离它最近的一层,最近的一层没有变量继续向上找,直到找到最外层函数,但完全不涉及全局变量
globals():print(globals()),返回一个字典,无论在函数内部打印还是在外部打印,结果都是全局变量与值的关系的字典,glocals()的结果共用一个空间,无论在哪里,只要字典中的值改变了,这个结果就会改变
locals():print(locals()),返回一个字典,结果是当前空间变量与值的关系的字典,如果没有变量就是空字典,如果在局部空间中,locals()结果中改变值,局部空间中的变量值不会改变(深拷贝),如果在全局空间,结果和globals()的结果相同,这时候改变字典中的值,全局空间的值就会改变.
b = 5
def test2():
    a = 1
    locals()["a"] = 2  # 只修改字典的值,
    print("第一a>>",a)  # 与a无关了,深拷贝
    globals()["b"] = 6  # 修改了b的值,共用空间
    print("第一b>>",b)

if __name__ == '__main__':
    test2()
print("第二b>>",b)
locals()["b"] = 3  # 修改了b的值,共用空间
print("第三b>>",b)
b = 5
def test2():
    a = 1
    print(locals(), end="
" * 2) #当前空间,有一个变量
    def func():
        print(locals(),end="
"*2) #当前空间,空字典
        print(globals(),end="
"*2) #全局空间
    func()

if __name__ == '__main__':
    test2()
print(locals(),end="
"*2) #当前空间,全局空间
print(globals(),end="
"*2) #全局空间

20.什么是闭包

在嵌套函数中,内层函数对外层函数的变量(非全局,非本层)的调用
作用:保存局部信息不被销毁,保证数据的安全性
应用:
    1.可以保存一些非全局变量但是不易被销毁、改变的数据。
	2.装饰器

21.列举你曾经使用过的标准库模块

os,sys,hashlib,collections,re,time,datetime,random,socket,threading,logging,Queue,json,pickle

22.列举你曾经使用过的第三方模块

Requests,MySQL,Django,Event,gevent

23.序列化模块在工作中用在哪个环节

序列化模块就是将一个常见的数据结构转化成一个特殊的序列,并且这个特殊的序列还可以反解回去。它的主要用途:文件读写数据,网络传输数据

24.请说出sys.path.append()的作用

添加自定义模块路径

25.实例化对象发生了什么事情

1.自动执行__new__方法开辟并返回一个对象空间
2.自动执行类中的__init__方法,并将这个对象空间(内存地址)传给__init__方法的第一个位置参数self
3.在__init__方法中通过self给对象空间封装属性

26.面向对象的三大特征

1.继承:单继承和多继承,子承父业,它可以使用现有类的所有功能,并在无需重新编		写原来的类的情况下对这些功能进行扩展
2.封装:就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信	   的类或者对象操作,对不可信的进行信息隐藏
3.多态:一个变量,多种形态,指一个类实例的相同方法在不同情形有不同表现形式。	    多态机制使具有不同内部结构的对象可以共享相同的外部接口

27.什么是面向对象,面向对象式编程的优势是什么

定义:就是一类相似功能函数的集合
使代码更清晰化,更合理化
拥有上帝视角看问题,类其实就是一个公共模板,对象就是从具体的模板实例化出来的

28.什么是鸭子类型

看起来像鸭子,它就是鸭子,对相同的功能定义了相同的名字,这样方便开发,两种方法互称鸭子类型,例如,list,tuple,str都有index方法,这种就是统一了规范,互为鸭子模型

29.写一下你学过的双下方法及调用方式

__init__初始化,给对象封装属性
__new__构造方法,新生成一个对象
__del__析构方法,当对象在内存中被释放时,触发执行
__len__计算长度
__hash__判断是否可哈希
__str__返回内容
__repr__原形毕露,返回其原始值
__call__对象+()触发执行call方法
__eq__同一类的两个实例比较时会触发
__item__对对象进行类似字典的操作就会触发该方法
__enter__上下文管理,进入时
__exit__上下文管理,出来时

30.手写一个单例模式

class A:
    a = None
    def __new__(cls, *args, **kwargs):
        if not cls.a: 
            cls.a = object.__new__(cls)
        return cls.a
obj1 = A()
print(obj1)
obj2 = A()
print(obj2)

31.issubclass 和 isinstance

isinstance(a,b):判断a是否是b类或者b类的派生类的实例化对象
issubclass(a,b):判断a类是否是b类或者b类的派生类的派生类

32.self 和 cls 参数的区别和联系

self传入的是一个类的实例化对象
cls传入的是一个类名
都是位置参数,都是隐形传参

33.类的约束

其实就是父类对子类进行约束
1.使用抽象类和抽象方法,由于该方案来源是Java和c#,所以使用频率很少
2.使用人为抛出异常的方案,只要子类用到父类的方法,就抛出错误

34.super的用法

跳过本类
单继承时,按照深度优先原则,查找下一类
多继承时,严格按照对象从属于类的mro顺序查找下一类

35.如果自己的类需要支持with语句,应该如何书写

具有__enter__ 和 __exit__ 方法

36.type元类与object类的关系

object是type元类的实例化对象 print(isinstance(object,type))
type类是object类的派生类 print(issubclass(type,object))

37.简述反射的作用及相关方法

作用:通过字符串的形式操作对象相关的属性
    hasattr 检测是否存在
    getattr 获取
    setattr 设置
    delattr 删除

38.python中如何判断一个对象是否可调用?如何定义一个类,使其对象本身变成可调用对象

# 第一种方法callable,返回True有可能调用失败,但是返回False,那绝对不能调用
def func():
 print(1)
func()
print(callable(func))
# 第二种方法,判断对象类型是否属于FunctionType,若为True,则可调用
from types import FunctionType
print(isinstance(func,FunctionType))
# 第三种方法,判断对象是否实现__call__方法
print(hasattr(func,'__call__'))
# 静态方法属于函数,类方法和实例方法分别依赖于类和对象,所以他们是method,其余我们自己定义的都是函数,函数就可调用
#若想让一个类的实例化对象可调用,可在类中定义__call__方法,即可实现

39.经典类与新式类的区别

经典类:在python2.2之前,一直使用的是经典类,经典类在基类的根什么都不写,采用深度优先遍历方案
新式类:在Python2.2之后出现了新式类,新式类的特点是基类的根是object类,python3中使用的都是新式类,默认继承object类,采用c3算法遍历原则,mro序列

40.如何区分函数和方法

函数是显性传参,不依赖于类和对象
方法是隐形传参,依赖于类和对象
类中的静态方法(@staticmethod),是函数
类中的类方法(@classmethod),是方法
from types import FuctionType,MethodType  (函数类,方法类)
python中一切皆对象,类在某种意义上也是一个对象,python中自定义的类,以及大多数内置类,str,dict等,都是type元类实例化得来的
python中一切皆对象,函数在某种意义上也是一个对象,它是从FunctionType这个类实例化出来的
python中一切皆对象,方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的

41.简单说一下类中的属性

property,将方法伪装成属性,调用时看起来像是调用类或者对象的属性,其实调用的是方法
优点:看起来更合理,遵循了统一访问原则
由于伪装成了属性,属性可以增删改查,所以配套有了setter 修改属性 deleter 删除属性(都是伪装的,执行时调用此方法)
class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的时候运行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的时候运行我啊')

#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
obj = Foo()
obj.AAA
obj.AAA = 'aaa'
del obj.AAA

42.类的私有成员有哪些,如何使用?

类的私有属性;类的私有方法;对象的私有属性;对象的私有方法(对象的方法不清楚,可能是函数当做对象,他自己的方法)
只能在类的内部使用

43.什么是异常,什么是异常处理,为什么要有异常处理,使用中应注意哪些事项?

异常:异常发生之后,程序就中断了
异常处理:代码发生异常时,通过某种手段不让程序中断,合理地跳过去
原因:增强用户的体验感;使代码更有健壮性,容错性
注意:1.异常处理慎重使用,因为比较消耗性能
    2.异常处理的所包含的代码区域尽量精简,不要把整段代码都写入try,而是针对个别可能会抛出异常的位置进行异常处理

44.异常处理中finally的用途?

finally不管出不出现异常都执行,如果有异常,在异常出现之前执行
用途:1. 关闭文件句柄,关闭数据库链接,保证数据安全
    2.函数return之前能够执行finally代码
    3.break之前可以执行finally

45.什么是操作系统,操作系统的作用,操作系统和软件的区别?

操作系统位于计算机硬件和软件之间,本质也是一个软件,就是一个协调,管理和控制计算机硬件资源和软件资源的控制程序
作用:1.隐藏了丑陋的硬件调用接口,为程序员提供简单清晰的应用程序
    2.将应用程序对硬件的竞态请求变的有序化
    3.当多个进程抢占一个CPU资源时,操作系统将你的执行变的合理有序
区别:操作系统由硬件保护,不能被用户修改

46.多道技术

1.空间上的复用:将内存分区域,一个内存可以同时加载多个进程(但是还没有做到真正意义上的隔离,各个软件之间可以互相访问,一个软件中病毒都会被传染,没有真正物理隔离)
2.时间上的复用:实现CPU在多个进程之间来会切换,并且保留状态(当进程遇到io阻塞或者长时间运行时,操作系统会将此进程挂起,保留状态,将CPU强行切换到另一个进程)

47.什么是进程,进程的三个状态?

正在进行的一个程序或者说一个任务就是进程,进程是计算机中最小的资源分配单位,而负责执行任务的是CPU
1.运行,CPU执行此进程
2.阻塞,遇到io阻塞
3.就绪,结束阻塞,CPU在运行别的进程

48.进程和程序的关系

程序仅仅是一堆代码而已,进程指的是程序的运行过程

49.七层协议

1.应用层,网络服务与最终用户的一个接口,常见协议:HTTP,FTP等
2.表示层,主要是对接收的数据进行解释,压缩和解压缩等,即把计算机能够识别的东西转化成人能够识别的东西(如图片,声音等)(五层协议合并到应用层)
3.会话层,通过传输层建立数据传输通路,在系统之间发起会话或者接受会话请求
4.传输层,定义传输数据的协议端口号,以及流控和差错校验,常见协议TCP,UDP
5.网络层,进行逻辑地址寻址,实现不同网络之间的路径选择,IP,ARP,路由协议
6.数据链路层,主要是将从物理层接收的数据进行Mac地址的封装和解封,对比特流进行分组(以太网协议)
7.物理层,建立,维护,断开物理连接,由网线,光纤等一系列物理介质组成,发送比特流

50.TCP/UDP协议

TCP:可靠的,面向连接的协议(通讯时必须先建立连接),传输效率低,面向字节流,如浏览器,文件传输程序
UDP:不可靠的,无连接的服务(通信时不用建立连接),传输效率高,视频,语音软件

51.三次握手和四次挥手


52.ARP协议,IP协议,端口协议,以太网协议,路由协议

mac地址:计算机网卡上记录的独一无二的地址
ARP协议:通过对方的ip地址获取到对方的mac地址
IP协议: 确定局域网(子网)的位置 
端口协议: 确定计算机软件在计算机的位置
以太网协议: 对比特流进行合理的分组  
路由协议:确定网络路径  

53.串行,并行,并发

串行:所有的任务一个一个的完成
并行:一个CPU完成多个任务,看起来像是同时完成的
并发:多个CPU执行多个任务,真正的同时完成

54.什么是C/S B/S 架构

C/S:基于客户端与服务端的架构,这种架构是从用户层面来划分的,这里的客户端一般泛指客户端的应用程序EXE,程序需要先安装后,才能在用户的电脑上运行,对用户的电脑操作系统环境依赖性较大.qq,微信
    优点:个性化设置,响应速度快
    缺点:开发.维护成本高,占用空间,用户固定
B/S:基于浏览器和服务端的架构,这种架构是从用户层面来划分的,只是这个客户端不需要大家去安装什么应用程序,只需在浏览器上通过HTTP请求服务端相关的资源,客户端就能进行正常的访问,谷歌浏览器,火狐浏览器
    优点:开发.维护成本低,用户不固定
    缺点:功能单一,没有个性化设置,响应速度相对慢

55.缓冲区的作用

 输入缓冲区,输出缓冲区. 存储少量数据,避免网络不稳,造成你传输数据时的卡顿,保持相对平稳,稳定

56.什么情况下触发粘包现象

1.接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
2.发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包)

57.手写通信连接循环


58.进程的相关注意点

  1. 第一种开启进程方式,函数法

1.Windows环境下,开启进程必须在__name__测试端口下进行
2.args传的值必须以元组形式,target,args名称不可改变(与函数不同)
3.进程消耗大(耗时间),主进程速度快,p.start()只是操作系统发出一个开辟一个子进程的信号,就继续执行主进程
4.子进程复制主进程if之上的内容,空间在内存中是独立的,修改与否与主进程无关
5.进程的name默认值为Process-1,可以实例化时name="自定义",也可以p.name = "自定义"

2.第二种方式,面向对象 进程是 类名-1 线程是 Thread-1

1.必须写上继承Process类
2.p = Process()时如果没传值,name默认继承父类,默认值为 类名-1
3.如果传值了name,构建__init__方法,必须继承父类super()的init方法,因为进程init方法还有其他参数,可以只覆盖name的
4.约束,必须有run方法,否者执行父类的,什么都没有,结果只执行了主进程

59. 进程的pid

pid是进程在内存中的唯一标识
在cmd终端输入tasklist查询所有进程的pid
在cmd终端输入tasklist|findstr python查询pycharm中多个进程的pid
在cmd终端输入tasklist|findstr pycharm查询主进程的pid
(在pycharm文件未关闭的前提下才可以找到time.sleep(50))

代码中获取:os.getpid() 本进程
          os.getppid() 父(主)进程

60. 验证进程之间的空间隔离

无论是可变还是不可变,主进程都不变,空间隔离了

#一个进程下的调用函数
name = "alex"
def task():
    global name
    name = "刚哥"

if __name__ == '__main__':
    task() 
    print(name)
    
#多个进程空间隔离
from multiprocessing import Process
import time

lst = [1,2]
def task():
    lst.append(3)
    print(f"子:{lst}")

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print(f"主:{lst}")

61. join阻塞与lock锁的区别

共同点:都可以把并发变成串行,保证了顺序
不同点:join人为设定顺序,lock让所有进程公平竞争,保证了公平性
join阻塞,阻止join以下的代码执行,直到阻塞结束
代码优化
if __name__ == '__main__':
    lst = []
    for i in range(3):
        p = Process(target=task,args=(i,)) #p是对象
        lst.append(p)
        p.start()
    for t in lst:
        t.join()
    print("==>主开始")
    
   #优化串行
if __name__ == '__main__':
    for i in range(3):
        p = Process(target=task,args=(i,)) #p是对象
        p.start()
        p.join()
    print("==>主开始")

62. 进程中的一些关键字,守护进程 p.daemon = Ture

p.terminate() 杀死子进程,由于开启子进程需要时间,杀死在摇篮
p.is_alive()  返回Ture or False,判断子进程是否活着,进行中才为Ture
守护进程:子进程守护主进程,只要主进程结束,子进程就结束了(主进程结不结束与子进程无关)(注意主线程的区别)
p.daemon = Ture,必须在子进程开启之前(p.start()之前)设置,否则报错

63. 什么是僵尸进程和孤儿进程,哪个有危害,为什么

僵尸进程:子进程结束后,在被主进程回收之前,都会进入僵尸状态
孤儿进程:主进程因为某种原因结束了,但子进程还在运行中,这些子进程就成了孤儿进程,这些子进程会被init进程回收
僵尸进程是有害的,如果主进程不对僵尸进程进行回收,就会有大量的僵尸进程产生,会占用内存,每个僵尸进程都会占用pid号

64. 进程之间的通信方式

1.基于文件通信
2.基于队列通信
3.基于管道通信

65. 关于lock互斥锁的死锁问题

lock互斥锁用的是同一把锁,未上锁时,并行或并发抢锁,上锁后串行,锁释放后公平竞争,连续两次产生死锁现象,整个过程中是同一把锁,但是因为工厂原因导致id不同

66. 队列的相关问题

from multiprocessing import Queue
q = Queue(2) 
q.put()#超过两个2个阻塞
print(q.get()) #超过两个2个阻塞
参数:block=False ,阻塞时报错
    timeout=3 ,阻塞3秒后报错

67. 生产者消费者模型

生产者:产生数据的
消费者:接收数据做进一步的处理
容器:队列(作用:起到缓冲的作用,平衡生产力和消费力,解耦)

68. Lock锁,GIL锁,递归锁 写法lock_A = lock_B = RLock (必须这么写)

lock锁:互斥锁,在一个进程或者线程中只能连续acquire一次,否则会发生死锁现象
GIL锁:全局解释器锁,cpython解释器自带的,保证了同一个进程的多个线程同一时刻只能有一个线程访问
递归锁:RLock,同一把锁,引用一次计数+1,释放一次计数-1,只要计数不为0,其他线程进程就抢不到,能够解决死锁现象
 优缺点:lock是自定义的锁,保证进程中的数据安全,容易出现死锁现象
 gil锁是解释器自带的锁,保证了解释器的资源数据的安全,单进程的多线程不能利用多核

69. 什么是socket套接字,为什么要有socket套接字

socket是处于应用层与传输层之间的抽象层,它是一组操作起来非常简单的接口(接受数据),此接口接收数据之后,交由操作系统
如果直接与操作系统数据交互非常麻烦,繁琐,socket对这些繁琐的操作高度的封装简化

70. 什么是进程,什么是线程

进程:正在进行的一个过程或者说一个任务,即在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后调用线程去执行代码
线程:在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程

71. 线程vs进程

1. 进程是资源单位, 线程是执行单位
2. 开启进程的开销非常大,比开启线程的开销大很多
3. 开启线程的速度非常快.要快几十倍到上百倍
4. 同一进程中线程线程之间可以共享数据,进程与进程之间需借助队列等方法实现通信
5.线程之间的pid(这个进程的)相同,进程与进程之间的pid不同

72. 守护线程具体工作流程(注意与守护进程的区别)

守护线程:子线程守护主线程,主线程结束了守护进程就结束了,主线程是等待所有的非守护子线程结束之后才结束

73. 信号量(好比上厕所,锁有多把,有上限) semaphore 英 [ˈseməfɔː(r)]

也是一种锁, 控制并发数量

74. 计算密集型选择多进程的并发(数量级少时线程用时少)

io密集型的选择单进程的多线程(io的一定是多线程)

多进程可以利用多核,当计算密集型时多条线同时进行,而多线程不能利用多核,只能多个线程之间来回切换,数量级大时,来回切换浪费时间

75. 进程池和线程池


76. 阻塞,非阻塞,同步,异步

1.阻塞:程序运行时遇到了io,程序挂起,CPU被操作系统切走
2.非阻塞:程序没有遇到io,或遇到IO但是我通过某种手段(协程),让cpu强行运行我的程序
3.同步:(发布任务的角度)提交一个任务,自任务开始运行直到此任务结束(可能有IO),返回一个返回值之后,我在提交下一个任务
4.异步:(发布任务的角度)一次提交多个任务,然后我就直接执行下一行代码.

77. 异步如何回收结果

1. 将所有的任务的结果统一回收
2. 完成一个任务,返回一个结果

78. 什么是回调函数

按顺序接收每个任务的结果,进行下一步处理

79. mysql 的事务属性

事务:由一组sql语句组成的逻辑处理单元.

   原子性(Atomicity):事务是一个原子操作单元。在当时原子是不可分割的最小元素,其对数据的修改,要么全部成功,要么全部都不成功。
    一致性(Consistent):事务开始到结束的时间段内,数据都必须保持一致状态。
    隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境执行。
    持久性(Durable):事务完成后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。