#Python3面试小问题

(1) websocket 协议:

   # HTTP1.0还是1.1,都存在这样的缺陷: 
    1. 多次连接带来的性能损耗(即便是HTTP1.1,每个单独的网页文件的请求和应答仍然需要使用各自的连接)。 
    2. HTTP协议的会话都是客户端向服务器发起的。服务器不能主动发送消息给客户端。某些需要服务器向客户端推送通知的场景,客户端需要不断轮询服务器。 
    3. HTTP是非状态性的,每次都要重新传输鉴别信息,否则一旦断开一次,服务器就不知道客户端是谁了。 
    4. HTTP请求头信息多,传送很重。

所以:

#websocket 协议:
  	定位: HTML5协议,实时,全双工通信,长连接
    客户端与服务端只建立一个TCP连接,可以使用更少的连接。
	WebSocket的服务端可以将数据推送到客户端,如实时将证券信息反馈到客户端,实时天气数据,比http请求响应模式更灵活。
	更轻量的协议头,减少数据传送量。
	一次握手成功之后,客户端和服务器之间就可以建立持久连接的双向传输数据通道,而且服务器不需要被动地等客户端的请求,服务器这边有新消息就可以通知客户端,化被动为主动。
此外,使用WebSocket时,不会像HTTP一样无状态,服务器会一直知道客户端的身份。服务器与客户端之间交换的标头信息也很小

原文:https://blog.csdn.net/antony9118/article/details/54343534

(2) 什么是Python,有什么好处

1.简单易学,一种解释性语言,俗称‘胶水语言‘,'脚本语言'
2.Python是FLOSS(开源):----阅读它的源代码、进行改动
3.可移植性:----它能够工作在不同平台上windows linux  Macintosh 等等
4.可扩展性和可嵌入性:----嵌入C/C++程序,从而向你的程序用户提供脚本功能,隐藏关键代码。
5.丰富的库:----标准库和第三方库,加快开发周期
6.数据库:----Python提供所有主要的商业数据库的接口。
7.GUI编程:----Python支持GUI可以创建和移植到许多系统调用。
8.规范的代码:---- Python 采用强制缩进的方式使得代码具有极佳的可读性。
9.面向对象 :----既支持面向过程的编程也支持面向对象的编程。

缺点:
1,运行慢
运行速度和C程序比要慢很多,因为Python是解释型语言,代码在执行时会一行一行地翻译成CPU能理解的机器码,这个翻译过程非常耗时,所以很慢。
2,代码安全性弱
代码不能加密。如果要发布你的Python程序实际上就是发布源代码。
3.Python 的 GIL 锁限制并发
Python 的另一个大问题是,对多处理器支持不好。GIL 是指 Python 全局解释器锁(Global Interpreter Lock)
当 Python 的默认解释器要执行字节码时,都需要先申请这个锁。这意味着,如果试图通过多线程扩展应用程序,将总是被这个全局解释器锁限制。

(3) 什么是pep8

PEP8是 Python的 编码规范。

中文解释规范:http://www.cnblogs.com/ajianbeyourself/p/4377933.html

(4) 对象的序列和反序列化

对象的序列化和反序列化 :
对象的序列化: 就是将Object转换成byte序列 
对象的反序列化: 将byte序列转换成Object
pickle模块实现Python对象结构的二进制协议序列化和反序列化。pickling将Python对象层次结构转换为字节流的过程。unpickling是相反操作,将字节流(二进制文件或类似字节的对象)转换回对象层次结构。

python中内置了很多序列化/反序列化的方式,最常用的有json、pickle、marshal这三种,http://www.cnblogs.com/yjmyzz/p/python-serialization-and-object-copy.html

(5) HTTP状态码

状态码	类别	原因短语
1XX	信息状态码(informational)	接收到的请求正在处理
2XX	成功状态码(Success)	请求正常处理完毕
3XX	重定向状态码(Redirection)	需要进行附加的操作完成请求
4XX	客户端错误状态码(Client Error)	服务器无法处理请求
5XX	服务器错误状态码(Server Error)	服务器处理请求出错

HTTP详细状态码:http://tool.oschina.net/commons?type=5
HTTP协议:https://blog.csdn.net/weixin_43097301/article/details/84290634

(6) 同步/异步IO

对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:
1. 等待数据准备 (Waiting for the data to be ready)
2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

#同步:必须等待任务结束并返回数据后,才能继续执行下面的操作
#异步:用户进程发起耗时操作之后,立刻就可以开始去做其它的事。当数据准备好了,就会切回之前的任务,避免等待时间

详细解释:http://www.cnblogs.com/Jeb15/p/6216866.html

(7)编译性语言和解释性语言

#编译型语言:程序执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,以后要运行的话就不用重复翻译了,直接使用编译的结果就行了,程序执行效率高,依赖编译器,跨平台性差些
#解释型语言:运行程序的时候才翻译,专门有一个解释器去进行翻译,每个语句都是执行的时候才翻译。效率比较低,依赖解释器,跨平台性好

(8)Python是怎样被执行的

使用C/C++之类的编译性语言编写的程序,是需要从源文件转换成计算机使用的机器语言,经过链接器链接之后形成了二进制的可执行文件。
运行该程序的时候,就可以把二进制程序从硬盘载入到内存中并运行。

 但是对于Python而言,python源码不需要编译成二进制代码,它可以直接从源代码运行程序。
 当我们运行python文件程序的时候,python解释器将源代码转换为字节码,然后再由python解释器来执行这些字节码。

(9) Python是怎么管理内存的

#第一个是对象引用计数机制
1.Python语言内部依靠引用计数来持续追踪内存中的对象,就是说,它的Python内部记录的对象有多少个引用,即引用计数,当对象被创建时就等于创建了一个引用计数,当对象不再需要时,这个对象的引用计数归零时,它将被垃圾收集机制处理掉。

#垃圾回收
1、当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。
2、垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。

		 标记清除 
		如果两个对象的引用计数都为1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非0,但实际上有效的引用计数为0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。 
		在实际操作中,并不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副本做任何的改动,都不会影响到对象生命周期的维护。 
		这个计数副本的唯一作用是寻找root object集合(该集合中的对象是不能被回收的)。当成功寻找到root object集合之后,首先将现在的内存链表一分为二,一条链表中维护root object集合,成为root链表,而另外一条链表中维护剩下的对象,成为unreachable链表。之所以要剖成两个链表,是基于这样的一种考虑:现在的unreachable可能存在被root链表中的对象,直接或间接引用的对象,这些对象是不能被回收的,一旦在标记的过程中,发现这样的对象,就将其从unreachable链表中移到root链表中;当完成标记后,unreachable链表中剩下的所有对象就是名副其实的垃圾对象了,接下来的垃圾回收只需限制在unreachable链表中即可。
	
		分代回收 
		从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。 
		举个例子来说明: 
		当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。

#内存池机制
1.Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
2.Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。
3.另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配内存存放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

管理内存:http://www.cnblogs.com/kaid/p/8735189.html

(10)TCP和UDP区别

#TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);
UDP是无连接的,即发送数据之前不需要建立连接

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;
UDP尽最大努力交付,即不保证可靠交付

3、Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

4.每一条TCP连接只能是点到点的;
UDP支持一对一,一对多,多对一和多对多的交互通信

5、TCP对系统资源要求较多,
UDP对系统资源要求较少。

TCP和UDP区别:https://blog.csdn.net/xiaobangkuaipao/article/details/76793702

(11)数据库中用到哪些锁

#事务的特性满足:ACID(原子性,一致性,隔离性,持久性)四特性,
	事务是恢复和并发控制的基本单位。原子性指的是事务是数据库的逻辑工作单位,事务中操作要么都做,要么都不做;一致性指的是事务的执行结果必须是使数据库从一个一致性状态变大另一个一致性状态,一致性和原子性是密切相关的;隔离性指的是一个事务执行不能被其他事务干扰;持久性指的是一个事务一旦提交,他对数据库中数据的改变就是永久性的。

#读/写锁
在处理并发的读或者写时,可以通过实现一个由两种类型的锁组成的锁系统来解决上面概述中的问题。这两种锁通常称为共享锁 排它锁,或者叫做读锁,写锁
读写锁可以分为三类,读者优先,写者优先和公开策略。	

#行级锁和表级锁	
行级锁是一种排他锁,防止其他事务修改此行;在使用以下语句时,Oracle会自动应用行级锁:
	INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];
	SELECT … FOR UPDATE语句允许用户一次锁定多条记录进行更新
	使用COMMIT或ROLLBACK语句释放锁

表级锁又分为5类:
	行共享 (ROW SHARE) – 禁止排他锁定表
	行排他(ROW EXCLUSIVE) – 禁止使用排他锁和共享锁
	共享锁(SHARE) - 锁定表,对记录只读不写,多个用户可以同时在同一个表上应用此锁
	共享行排他(SHARE ROW EXCLUSIVE) – 比共享锁更多的限制,禁止使用共享锁及更高的锁
	排他(EXCLUSIVE) – 限制最强的表锁,仅允许其他用户查询该表的行。禁止修改和锁定表。
	
#悲观锁和乐观锁
乐观锁认为一个用户读数据的时候,别人不会去写自己所读的数据;悲观锁就刚好相反,觉得自己读数据库的时候,别人可能刚好在写自己刚读的数据,

mysql 引擎,锁:https://blog.csdn.net/weixin_43097301/article/details/84954485

(12)Python提供哪些数据类型

1、字符串
2、布尔类型
3、整数
4、浮点数
5、数字
6、列表
7、元组
8、字典
9、日期

数据类型和增删改查:https://www.cnblogs.com/linjiqin/p/3608541.html

(13)什么是lambda

#Lambda 表达式"(lambda expression)是一个匿名函数
编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。

将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。
例如,执行语句add=lambda x, y: x+y,定义了加法函数lambda x, y: x+y,并将其赋值给变量add,这样变量add便成为具有加法功能的函数。例如,执行add(1,2),输出为3。

将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。
例如,为了把标准库time中的函数sleep的功能屏蔽(Mock),我们可以在程序初始化时调用:time.sleep=lambda x:None。这样,在后续代码中调用time库的sleep函数将不会执行原有的功能。例如,执行time.sleep(3)时,程序不会休眠3秒钟,而是什么都不做。

将lambda函数作为其他函数的返回值,返回给调用者。
函数的返回值也可以是函数。例如return lambda x, y: x+y返回一个加法函数。这时,lambda函数实际上是定义在某个函数内部的函数,称之为嵌套函数,或者内部函数。对应的,将包含嵌套函数的函数称之为外部函数。内部函数能够访问外部函数的局部变量,这个特性是闭包(Closure)编程的基础,在这里我们不展开。


将lambda函数作为参数传递给其他函数。
部分Python内置函数接收函数作为参数。典型的此类内置函数有这些。

lambda详细:https://blog.csdn.net/zjuxsl/article/details/79437563

(14)pass关键字

当你在编写一个程序时,执行语句部分思路还没有完成,这时你可以用pass语句来占位,也可以当做是一个标记,
# 如果在开发程序时,不希望立刻编写分支内部的代码
# 可以使用 pass 关键字,表示一个占位符,能够保证程序的代码结构正确!
# 程序运行时,pass 关键字不会执行任何的操作

(15)什么是迭代器

#迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:

#生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。


菜鸟教程:http://www.runoob.com/python3/python3-iterator-generator.html

(16)什么是文本字符串

由字母、符号 和中文 组合而成的字符串。
主要是使用字符串的split()与正则的re.split()方法进行拆分。前者每次处理一种分隔符,后者一次性可以处理多个分割字符。

(17)深拷贝和浅拷贝

copy(),deepcopy()的区别
1,变量:是一个系统表的元素,拥有指向对象的连接空间
2,对象:被分配的一块内存,存储其所代表的值
3,引用:是自动形成的从变量到对象的指针
4,注意:类型(int类型,long类型(python3已去除long类型,只剩下int类型的数据))属于对象,不是变量
5,不可变对象:一旦创建就不可修改的对象,包括字符串、元组、数字
6,可变对象:可以修改的对象,包括列表、字典。

#不可变对象类型,
没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。
一句话就是,不可变类型,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。

#可变对象类型
=浅拷贝:值相等,地址相等 
copy浅拷贝:值相等,地址不相等 
deepcopy深拷贝:值相等,地址不相等
import copy

a = [1, 2, 3, 4, ['a', 'b']]  # 原始对象

b = a  # 赋值,传对象的引用
c = copy.copy(a)  # 对象拷贝,浅拷贝
d = copy.deepcopy(a)  # 对象拷贝,深拷贝

a.append(5)  # 修改对象a
a[4].append('c')  # 修改对象a中的['a', 'b']数组对象

print('a = ', a)
print('b = ', b)
print('c = ', c)
print('d = ', d)

#(输出)
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
deepcopy的时候会将复杂对象的每一层复制一个单独的个体出来。
copy是对已存在的东西进行复制[1, 2, 3, 4, [‘a’, ‘b’]],如果存在的东西内部改变了,也会进行改变,比如这里的list[‘a’, ‘b’]内部发生了改变

深拷贝和浅拷贝https://blog.csdn.net/u014745194/article/details/70271868

(18)怎么把number转字符串

方法1:字符转数字 int(str)
方法2:
import string 
tt='555'
ts=string.atoi(tt)
ts即为tt转换成的数字
转换为浮点数 string.atof(tt)

python 字符串和整数的相互转换https://blog.csdn.net/u013066730/article/details/51111676

(19)什么是模块,什么是包,什么是库

包 --是一个有层次的文件目录结构:它定义了由n个模块或n个子包组成的python应用程序执行环境
库--是具有相关功能模块的集合:标准库、第三方库以及自定义模块。
模块 --是一个文件:包含并且有组织的代码片段为模块

(20)Linux下如何让Python文件或者shell脚本变成可执行的

1.首先创建好文件(cd 到需要放置的目录下)
touch myTest.py

2. 编辑myTest.py
vi myTest.py
在里面添加内容
#!/usr/bin/env python3
前面需要标注解释器为Python3,当然是根据自身的python解释器的版本然后添加需要添加的代码
print('hello, world!')
然后进入命令模式,:wq保存退出vi

3. 更改myTest.py的权限,根据需要更改,这里主要用于测试,不放设置777
chmod 777 myTest.py

4. 这是可以在当前目录中直接运行myTest.py(类似windows中直接执行exe)
./myTest.py

(21)Python里怎么执行shell命令

1. 使用os.system("cmd")
特点是执行的时候程序会打出cmd在linux上执行的信息。
import os
os.system("ls") 

2. 使用Popen模块产生新的process
Popen方法不会打印出cmd在linux上执行的信息
Popen函数有一个缺陷,就是它是一个阻塞的方法。如果运行cmd时产生的内容非常多,函数非常容易阻塞住。
解决办法是不使用wait()方法,但是也不能获得执行的返回值了。
from subprocess import Popen, PIPE
output = os.popen('cat /proc/cpuinfo')
print output.read()
通过 os.popen() 返回的是 file read 的对象,对其进行读取 read() 的操作可以看到执行的输出。但是无法读取程序执行的返回值)

3. 使用commands.getstatusoutput方法
这个方法也不会打印出cmd在linux上执行的信息。这个方法唯一的优点是,它不是一个阻塞的方法。即没有Popen函数阻塞的问题。、
import commands
status, output = commands.getstatusoutput("ls") 
只获得output和status的方法:
commands.getoutput("ls")  
commands.getstatus("ls") 

Python里怎么执行shell命令详细:https://www.cnblogs.com/qytang/p/5566860.html

(22)Python里怎么使用随机数

在 Python 中用于生成随机数的模块是 random,在使用前需要 import. 如下例子可以酌情列举:

random.random():生成一个 0-1 之间的随机浮点数;
random.uniform(a, b):生成[a,b]之间的浮点数;
random.randint(a, b):生成[a,b]之间的整数;
random.randrange(a, b, step):在指定的集合[a,b)中,以 step 为基数随机取一个数;
random.choice(sequence):从特定序列中随机取一个元素,这里的序列可以是字符串,列表,元组等。

(23)MVC是什么

mvc模式是一个运用在软件工程中的设计模式。mvc模式脱离了以前简单的web服务设计逻辑,将开发,测试和维护分离。
在MVC模式中,应用被分解为相互作用的模块,模型,视图,控制。目的在于分离输入(control),处理逻辑(model),输出格式(view)。

设计模式之MVC模式:https://www.cnblogs.com/lizhitai/p/4449540.html

(24)同或、异或怎么操作

按位的运算,都按位的运算,都是把参加运算的数的二进制形式进行运算。

1.与运算:A与B值均为1时,A、B与的运算结果才为1,否则为0 (运算符:&)
2.或运算:A或B值为1时,A、B或的运算结果才为1,否则为0  (运算符:|)
3.异或运算:A与B不同为1时,A、B的预算结果才为1,否则为0  (运算符:^)
4.按位翻转(按位取反):将内存中表示数字的2进制数取反 ,0取1,1取0 (运算符:~)

python中 “与,或,异或” :http://www.cnblogs.com/pythonworld/p/3520627.html

(25)矩阵转置

将矩阵的行列互换得到的新矩阵称为转置矩阵,转置矩阵的行列式不变。
python的numpy库进行转置

数组转置的三种方法:https://blog.csdn.net/Asher117/article/details/82934857

(26)口述贝叶斯公式

贝叶斯定理是关于随机事件A和B的条件概率(或边缘概率)的一则定理。其中P(A|B)是在B发生的情况下A发生的可能性。
 贝叶斯公式就是当已知结果,问导致这个结果的第i原因的可能性是多少?执果索因!

浅谈全概率公式和贝叶斯公式:https://blog.csdn.net/Hearthougan/article/details/75174210

(27)Help和Dir函数

help()函数是查看函数或模块用途的详细说明,比如:help('re'),help('re.split')

而dir()函数是查看函数或模块内的操作方法都有什么,输出的是方法列表。

(28)django数据库操作

python 自带SQLite数据库,Django支持各种主流的数据库
首先在settings.py文件配置数据库

在mysql数据中创建一个djangodb的数据库,然后在mysite/__init__.py文件中加入以下代码
import pymysql
pymysql.install_as_MySQLdb()

命令行运行:做迁移  也可以在pycharm中manage.py中进行
E:\WWWROOT\python\mysite>python manage.py makemigrations
E:\WWWROOT\python\mysite>python manage.py migrate

django基础之数据库操作:https://www.cnblogs.com/ginvip/p/6894690.html

(29)range 和 x range区别

xrange 用法与 range 完全相同,所不同的是生成的不是一个list对象,而是一个生成器。
range会直接生成一个list对象:
而xrange则不会直接生成一个list,而是每次调用返回其中的一个值:

在这里插入图片描述
range 和 x range区别:https://www.cnblogs.com/xiezhiyang/p/6613094.html

(30)HTTP中的会话,django中如何使用会话

1 Cookie 机制:cookie 是服务器产生的一段随机字符串。它的主要内容包括:名字,值,过期时间,路径与域等信息。然后服务器将其发送给客户端。在后续的请求中,cookie 会附在请求资源的 HTTP 请求头上,发送给服务器。
2 Session 机制:为了让cookie信息安全,Session 机制是一个服务器端的机制。它会将信息保存服务器端 。

Django 为我们提供了一个通用的 Session 框架
默认 Session 数据保存到数据库中,可以在 settings.py 中看到配置信息项目
在这里插入图片描述

1)保存到缓存中,在 settings.py 中增加 SESSION_ENGINE 配置。
在这里插入图片描述
在这里插入图片描述
2)保存到文件中,在 settings.py 中增加 SESSION_ENGINE 配置。

在这里插入图片描述
3)保存到 cookie 中,在 settings.py 中增加 SESSION_ENGINE 配置。
在这里插入图片描述
具体配置:https://www.jianshu.com/p/d2f6c3d9dc6d

(31)Python多继承,调用父类方法是广度优先还是深度优先

python2 是深度优先,python3 是广度优先,

(32)Scrapy

编辑分类
Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。

(33)Django MTV模式和MVC模式的区别

MVC:Model 代表数据存取层,View 代表的是系统中选择显示什么和怎么显示的部分,Controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。

  M ,数据存取部分,由django数据库层处理,本章要讲述的内容。 
  V ,选择显示哪些数据要显示以及怎样显示的部分,由视图和模板处理。
  C ,根据用户输入委派视图的部分,由 Django 框架根据 URLconf 设置,对给定 URL 调用适当的 Python 函数。

MTV :Django 里更关注的是模型(Model)、模板(Template)和视图(Views), Django 也被称为 MTV 框架 :

 M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效
 T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
 V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。

(34)Django 的组件

1. 分页器的使用
2. forms组件
3. 中间件views处理函数
4. cookie和session
5. Django用户认证组件

(35)http访问django经过那几个组件?

1. 用户通过浏览器请求一个页面
2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求
3.URLConf通过urls.py文件和请求的URL找到相应的View
4.View Middlewares被访问,它同样可以对request做一些处理或者直接返回response
5.调用View中的函数
6.View中的方法可以选择性的通过Models访问底层的数据
7.所有的Model-to-DB的交互都是通过manager完成的
8.如果需要,Views可以使用一个特殊的Context
9.Context被传给Template用来生成页面
    a.Template使用Filters和Tags去渲染输出
    b.输出被返回到View
    c.HTTPResponse被发送到Response Middlewares
    d.任何Response Middlewares都可以丰富response或者返回一个完全不同的response
    e.Response返回到浏览器,呈现给用户

(36)Sql语句优化

优化sql语句,避免消耗跟多内存,具体如下:
Sql语句优化:https://www.cnblogs.com/parryyang/p/5711537.html

(37)mysql的引擎又哪几种,你工作中用的哪一种,为什么用它,有什么优缺点

InnoDB存储引擎
InnoDB是Mysql数据库的一种存储引擎。InnoDB给Mysql的表提供了 事务、回滚、崩溃修复能力、多版本并发控制的事务安全、间隙锁(可以有效的防止幻读的出现)、支持辅助索引、聚簇索引、自适应hash索引、支持热备、行级锁。还有InnoDB是Mysql上唯一一个提供了外键约束的引擎。
InnoDB存储引擎中,创建的表的表结构是单独存储的并且存储在.frm文件中。数据和索引存储在一起的并且存储在表空间中。但是默认情况下mysql会将数据库的所有InnoDB表存储在一个表空间中的。其实这种方式管理起来非常的不方便而且还不支持高级功能所以建议每个表存储为一个表空间实现方式为:使用服务器变量innodb_file_per_table = 1。
如果需要频繁的进行更新、删除操作的数据库也可选择InnoDB存储引擎。因为该存储引擎可以实现事务提交和回滚。

MyISAM存储引擎
MyISAM存储引擎是Mysql中常见的存储引擎,MyISAM存储引擎是基于ISAM存储引擎发展起来的。MyISAM支持全文索引、压缩存放、空间索引(空间函数)、表级锁、延迟更新索引键。但是MyISAM不支持事务、行级锁、更无法忍受的是崩溃后不能保证完全恢复(只能手动修复)。
MyISAM存储引擎的表存储成3个文件。文件的名字和表的名字相同。扩展名包含frm、MYD、MYI。其中FRM为扩展名的文件存储表的结构;MYD为扩展名的文件存储数据,其是MYData的缩写;MYI为扩展名的文件存储索引,其为MYIndex的缩写。
MyISAM存储引擎的插入数据很快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM存储引擎能够实现处理的高效率。如果应用的完整性、并发性要求很低,也可以选择MyISAM存储引擎。

MEMORY存储引擎
MEMORY存储引擎是Mysql中的一类特殊的存储引擎。其使用存储在内存中的内存来创建表,而且所有数据保存在内存中。数据安全性很低,但是查找和插入速度很快。如果内存出现异常就会影响到数据的完整性,如果重启或关机,表中的所有数据就会丢失,因此基于MEMORY存储引擎的表的生命周期很短,一般都是一次性的。适用于某些特殊场景像查找和映射,缓存周期性的聚合数据等等。

NDB 集群引擎
作为sql和NDB元素协议之间的接口,用于mysql,ndb集群存储引擎,分布式等

mysql的引擎:https://blog.csdn.net/weixin_43097301/article/details/84954485

(38)数据库死锁的原因及解决方法

所谓死锁DeadLock: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等带的进程称为死锁进程.表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB.

死锁的关键在于:两个(或以上)的Session(会话)加锁的顺序不一致。那么对应的解决死锁问题的关键就是:让不同的session加锁有次序

详细处理:https://blog.csdn.net/hexieshangwang/article/details/47189213

(39)redis有哪几种数据结构

1、String
    可以是字符串,整数或者浮点数,对整个字符串或者字符串中的一部分执行操作,对整个整数或者浮点执行自增(increment)或者自减(decrement)操作。
字符串命令:
    ①get、获取存储在指定键中的值
    ②set、设置存储在指定键中的值
    ③del、删除存储在指定键中的值(这个命令可以用于所有的类型)
  
  2、list
    一个链表,链表上的每个节点都包含了一个字符串,虫链表的两端推入或者弹出元素,根据偏移量对链表进行修剪(trim),读取单个或者多个元素,根据值查找或者移除元素。
列表命令:
    ①rpush或lpush  将给定值推入列表的  右端或者左端
    ②lrange、获取列表在指定范围上的所有值
    ③lindex、获取列表在指定范围上的单个元素
    ④lpop、rpop从列表的左端弹出一个值,并返回被弹出的值
  
    
3、set
    包含字符串的无序收集器(unordered collection)、并且被包含的每个字符串都是独一无二的。添加,获取,移除单个元素,检查一个元素是否存在于集合中,计算交集,并集,差集,从集合里面随机获取元素。
 集合命令:
    ①sadd、将给定元素添加到集合
    ②smembers、返回集合包含的所有元素
    ③sismember、检查指定元素是否存在于集合中
    ④srem、检查指定元素是否存在于集合中,那么移除这个元素
 
 4、hash
包含键值对无序散列表,添加,获取,移除当键值对,获取所有键值对。
散列命令:
    ①hset、在散列里面关联起指定的键值对
    ②hget、获取指定散列键的值
    ③hgetall、获取散列包含的所有键值对
    ④hdel、如果给定键存在于散列里面,那么移除这个键
 
5、zset
    字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定。添加,获取,删除单个元素,根据分值范围(range)或者成员来获取元素。
有序集合命令:
①zadd、将一个带有给定分值的成员添加到有序集合里面
②zrange、根据元素在有序排列中所处的位置,从有序集合里面获取多个元素
③zrangebyscore、获取有序集合在给定分值范围内的所有元素
④zrem、如果指定成员存在于有序集合中,那么移除这个成员

(40)如何用redis做缓存系统/消息队列

缓存:即用户请求数据时,先从redis数据中访问,如没有则从数据库中的数据取出来,然后存入redis,设置过期时间。

Redis实现先进先出队列
Redis实现FIFO很容易,只需要一个List对象从头取数据,从尾部塞数据即可实现。例如lpush存数据,brpop取数据。

Redis实现优先级队列
首先brpop和blpop是支持多list读取的,比如brpop lista listb 0 命令就可以实现先从lista读取数据,读取完lista的数据再去读取listb的数据。

redis实现消息队列:https://blog.csdn.net/lansetiankong12/article/details/52384052
缓存具体实现代码示列:http://www.cnblogs.com/ssyfj/p/8608650.html

(41)数据库事务的特性,四种隔离级别,以及在并发事务下会造成什么影响

⑴ 原子性(Atomicity)
  原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

⑵ 一致性(Consistency)
  一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  
⑶ 隔离性(Isolation)
  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

⑷ 持久性(Durability)
  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

影响:脏读、不可重复读、幻读的发生

脏读是 :指在一个事务处理过程里读取了另一个未提交的事务中的数据。
不可重复读是 :指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
幻读是:事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
现在来看看MySQL数据库为我们提供的四种隔离级别:
  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
  ③ Read committed (读已提交):可避免脏读的发生。
  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
  
  @root>set 表名字 = '隔离级别'

(42)对restful API的理解

一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

URL结尾不应该包含斜杠“/”
URL中不能有动词
正斜杠分隔符”/“必须用来指示层级关系
URL路径中首选小写字母
URL路径名词均为复数
状态码:服务器向用户返回的状态码和提示信息,使用标准的HTTP状态码
每一个uri代表一种资源;
客户端和服务器之间,传递这种资源的某种表现层;
客户端通过四个HTTP动词(GET、POST、DELETE、PUT),对服务器端资源进行操作,实现"表现层状态转化"(增删改查)。
使用JSON不使用XML
等等,,,

详细:http://www.runoob.com/w3cnote/restful-architecture.html

(43)http的标准方法,分别描述一下

1	GET	请求指定的页面信息,并返回实体主体。
2	HEAD	类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3	POST	向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。
数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4	PUT	从客户端向服务器传送的数据取代指定的文档的内容。
5	DELETE	请求服务器删除指定的页面。
6	CONNECT	HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7	OPTIONS	允许客户端查看服务器的性能。
8	TRACE	回显服务器收到的请求,主要用于测试或诊断。

(44)http状态码200/301/403/是什么意思,3开头4开头的都是什么意思

200     成功处理了请求,一般情况下都是返回此状态码;
 
3xx (重定向) 重定向代码,也是常见的代码
300   (多种选择)  针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。 
301   (永久移动)  请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 
302   (临时移动)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 
303   (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。 
304   (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 
305   (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。 
307   (临时重定向)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

4开头的http状态码表示请求出错
400    服务器不理解请求的语法。 
401   请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 
403   服务器拒绝请求。 
404   服务器找不到请求的网页。 
405   禁用请求中指定的方法。 
406   无法使用请求的内容特性响应请求的网页。 
407   此状态代码与 401类似,但指定请求者应当授权使用代理。 
408   服务器等候请求时发生超时。 

500   (服务器内部错误)  服务器遇到错误,无法完成请求。 
501   (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。 
502   (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。 
503   (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。 
504   (网关超时)  服务器作为网关或代理,但是没有及时从上游服务器收到请求。 
505   (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

(45)http请求头与响应头

请求示列:
在这里插入图片描述
响应示列:
在这里插入图片描述
http请求头与响应头的格式:https://blog.csdn.net/weixin_43097301/article/details/84290634
http请求头与响应头各字段解释:https://blog.csdn.net/weixin_43097301/article/details/88630895

(46)对进程,线程,协程的理解

并发
任务数大于cpu核载,通过系统的各种任务跳读算法,是任务“在一起”执行任务! 假的多任务

并行
任务数小于cpu核数,即任务真的在一起执行

进程
拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

线程
拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。线程不拥有系统资源,只有运行必须的一些数据结构;它与父进程的其它线程共享该进程所拥有的全部资源。线程可以创建和撤消线程,从而实现程序的并发执行。一般,线程具有就绪、阻塞和运行三种基本状态。

协程
和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
一个程序可以包含多个协程,可以对比与一个进程包含多个线程,因而下面我们来比较协程和线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。

(46)异步IO和多路复用
IO多路复用:它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程,进程等待数据接收完毕,再执行操作。

异步io:它受到一个asynchronous read(读的指令)之后,首先它会立刻返回,所以不会对用户进程产生任何block(阻塞)。然后,kernel(内核)会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal(信号),告诉它read操作完成了。

select 
它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。   
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。 
另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。

poll 
它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。 
一般也不用它,相当于过渡阶段

epoll 
公认为Linux2.6下性能最好的多路I/O就绪通知方法。windows不支持 
没有最大文件描述符数量的限制。 
比如100个连接,有两个活跃了,epoll会告诉用户这两个两个活跃了,直接取就ok了,而select是循环一遍。 
  
Level_triggered(水平触发):
当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!

Edge_triggered(边缘触发):
当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!

几种IO模型的触发方式
select(),poll()模型都是水平触发模式,
信号驱动IO是边缘触发模式,
epoll()模型即支持水平触发,也支持边缘触发,默认是水平触发。

摘要:https://blog.csdn.net/weixin_43097301/article/details/84781158
摘要:https://blog.csdn.net/fgf00/article/details/52793739

(47)socket网络编程

在这里插入图片描述
  先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

(48)函数式编程中的fliter(),map(),reduce(),apply()

map()函数接收两个参数,一个是函数,一个是可迭代的对象,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
>>> map(lambda x:x*2,xrange(4))
[0, 2, 4, 6]

reduce()函数即为化简,它是这样一个过程:每次迭代,将上一次的迭代结果与下一个元素一同执行一个二元的func函数。
这里面函数必须有俩个参数。
reduce(lambda x,y :x*y,xrange(1,10)) 
#(输出)362880   #1x2x3x4x5x6x7x8x9
reduce(lambda x,y :x*y,xrange(1,10),0.5)
#(输出)181440.0  #1x2x3x4x5x6x7x8x9x0.5

fliter()该内建函数的作用相当于一个筛子。func函数是一个布尔函数,filter()调用这个布尔函数,将每个seq中的元素依次过一遍筛子,选出使func返回值是Ture的元素的序列。
filter(lambda s:s and s.strip(),["A","",None,"C"])
#(输出)['A', 'C']     #即判断是否满足条件,

apply()   #apply()已经被从Python1.6开始被摒弃淘汰
apply()间接地调用函数,apply()的返回值就是func()的返回值,apply()的元素参数是有序的,元素的顺序必须和func()形式参数的顺序一致
def say(a, b): 
  print a, b
apply(say,("hello", "python"))
#(输出)hello python

(49)手写单例模式,至少2种方法

1. 重写__new__方法
通过重写__new__方法继承自该类的类只能创建一个实例
class Singleton(object):
def __new__(cls, *args, **kwargs):
    if not hasattr(cls, '_instance'):  #判断类本身是否含有该'_instance'属性,没有则添加
        temp = super(Singleton, cls)  #父类object
        cls._instance = temp.__new__(cls, *args, **kwargs)
    return cls._instance

class MyClass(Singleton):
    p = '单例类'
    
if __name__ == '__main__':
    e1 = MyClass()
    e2 = MyClass()
    if e1 is e2:
        print(1)
    else:
        print(0)
--------------------------------------------------------------
2. 使用装饰器
  实现装饰器之后,对类进行装饰即可实现一个单例类
def singleton(cls, *args, **kwargs)
    instances = {}
    def get_instance():
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
            return instance[cls]
        return get_instance

@singleton
class MyClass:
    p = '单例类'
    
if __name__ == '__main__':
    e1 = MyClass()
    e2 = MyClass()
    if e1 is e2:
        print(1)
    else:
        print(0)

(50)手写裴波那契数列,快速排序(用递归思想)

def recur_fibo(n): """递归函数输出斐波那契数列"""
	if n <= 1:
		return n
	else:
		return(recur_fibo(n-1) + recur_fibo(n-2))
		

nterms = int(input("您要输出几项? ")) # 获取用户输入
if nterms <= 0:  # 检查输入的数字是否正确
	print("输入正数")
else:
	print("斐波那契数列:")
	for i in range(nterms):
		print(recur_fibo(i))
#(输出):
您要输出几项? 10
斐波那契数列:
0
1
1
2
3
5
8
13
21
34

def QuickSort(myList,start,end):
    #判断low是否小于high,如果为false,直接返回
    if start < end:
        i,j = start,end
        #设置基准数
        base = myList[i]

        while i < j:
            #如果列表后边的数,比基准数大或相等,则前移一位直到有比基准数小的数出现
            while (i < j) and (myList[j] >= base):
                j = j - 1

            #如找到,则把第j个元素赋值给第个元素i,此时表中i,j个元素相等
            myList[i] = myList[j]

            #同样的方式比较前半区
            while (i < j) and (myList[i] <= base):
                i = i + 1
            myList[j] = myList[i]
        #做完第一轮比较之后,列表被分成了两个半区,并且i=j,需要将这个数设置回base
        myList[i] = base

        #递归前后半区
        QuickSort(myList, start, i - 1)
        QuickSort(myList, j + 1, end)
    return myList


myList = [49,38,65,97,76,13,27,49]
print("Quick Sort: ")
QuickSort(myList,0,len(myList)-1)
print(myList)

(51)yield作用,应用场景

yield是一个常用于python函数定义中的关键字,它的作用是返回一个可以用来迭代(for循环)的生成器,它的应用场景通常为一个需要返回一系列值的,含有循环的函数中。

迭代器是一个对象,这种对象每次只能调取一个数据元素。对迭代器不断调用 next() 方法(将迭代起变量放入next()中当参数),则可以依次获取下一个元素;当迭代器中没有元素时,调用 next() 方法会抛出 StopIteration(停止迭代) 异常。迭代器的 iter() 方法返回迭代器自身;因此迭代器也是可迭代的。

生成器函数是一种特殊的函数,它的函数内部含有yield表达式,调用它会返回一个特殊的迭代器,称生成器。
for 循环会调用__ iter__ 函数,获取一个生成器;而后调用 next 函数,将生成器中的下一个值赋值给 x;再执行循环体。因此,

应用场景:
数据访问:容器内的元素数量非常多,或者容器内的元素体积非常大,我们只取前几个数据的时候,yield能节省巨大的时间、空间开销,不用去for遍历容器。

协程:yield from
协程是一种用户态的轻量级线程(线程是系统级别的它们由操作系统调度,而协程则是程序级别的由程序根据需要自己调度)

协程的优点:
  (1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
  (2)无需原子操作锁定及同步的开销
  (3)方便切换控制流,简化编程模型
  (4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

协程的缺点:
  (1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  (2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值