一、前期复习
1、C/S架构与B/S架构:
C/S架构:客服端 服务器模式
B/S架构:浏览器 服务器模式
B/S架构的客服端对PC机的性能要求较低。统一了应用的接口。B/S架构隶属于C/S架构。
2、TCP/UDP的区别:
TCP:面向连接,可靠的,面向字节流
UDP:不面向了解,不可靠,速度快,面向数据包的
3、TCP会发生粘包:
粘包:数据混乱。发送端发送了数据后,接收端不知道应该如何去接收,导致数据混乱。
合包机制:Nagle算法
拆包机制
注意:只有TCP协议才会发生粘包。
4、arp协议:
通过目标的IP地址获取到目标的MAC地址。
5、OSI五层模型:
应用层: http, https, ftp
传输层: tcp, udp
网络层: ip协议
数据链路层: arp协议 网卡
物理层: 网线,电信号,集线器
6、交换机与路由器的区别:
交换机主要用来组织局域网,进行同一网段之间的信息传输。
路由器主要用来跨网段的信息传输,路由出最佳路径。
7、交换机的通信方式
单播:点对点
广播:吼一嗓子
组播:点对多(一组或多台)
8、如何判断两台电脑是否处于同一网段?
子网掩码 & ip地址
9、并行和并发?
并行:同一时间点多个任务同时进行
并发:在统一时间段内多个任务同时进行
10、进程和线程的区别?
进程:是资源分配的基本单位
线程:是最小的执行单位,线程不能独立拥有资源,必须依赖于所属进程。
当计算密集时,多进程比较好。IO密集时,使用多线程。
11、锁
GIL锁:全局解释锁。锁的是线程,宝成同一时间只允许一个线程访问CPU。
互斥锁:一把锁配一把钥匙。主要用于保护数据安全
共享资源,又叫做临界资源、共享代码,又叫做临界代码。
对临界资源进行操作时,一定要加锁。
递归锁:一把万能 钥匙配好多把锁。
12、信号量
也是用来保护数据安全的。一把锁配多把钥匙。
13、事件:
wait( ):判断is_set的bool值,如果为True,wait是非阻塞。
set:将is_set的bool值设置为True。
is_set:标识
clear:将is_set的bool值设置为False
14、多线程:
条件:Condition
定时器:Timer(t, func)
15、多进程之间的通信:
队列和管道
队列是安全的,队列=管道+锁
管道是不安全的。
16、队列实现生产者消费者模型
这个模型主要是为了解耦
17、进程池的模块:Pool
p.map
p.apply( ):同步提交任务
p.apply_async( ):异步提交任务
回调函数:在进程池中,是父进程调用的回调函数。
二、进程池和线程池
1、同一个进程内的队列(多线程)
优先级队列:queue.PriorityQueue( )
q.put( ) 接收的是一个元组
元组中的第一个参数:表示当前数据的优先级
元组中的第二个参数:需要存放到队列的数据
优先级比较:(首先保证整个队列中,所有表示优先级的东西必须一致)
① int:比较数值大小
② str:比较字符串的大小,从第一个字符的ASCII码开始比较
2、线程池
在一个池子里,放固定数量的线程,这些线程等待任务,一旦有任务来,就有线程自发的去执行任务。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor 2 from multiprocessing import Pool 3 4 # concurrent.futures 这个模块是异步调用的机制 5 # concurrent.futures 提交任务都是用submit 6 # for + submit 多个任务的提交 7 # shutdown 是等效于Pool中的close+join,是指不允许再继续向池中增加任务,然后让父进程(线程)等待池中所有进程执行完所有任务。 8 9 # from multiprocessing import Pool.apply / apply_async 10 import time 11 12 def func(num): 13 sum = 0 14 for i in range(num): 15 for j in range(i): 16 for x in range(j): 17 sum += x ** 2 18 print(sum) 19 20 if __name__ == '__main__': 21 pass 22 # pool的进程池的效率演示 23 # p = Pool(5) 24 # start = time.time() 25 # for i in range(100): 26 # p.apply_async(func,args=(i,)) 27 # p.close() 28 # p.join() 29 # print('Pool进程池的效率时间是%s'%(time.time() - start)) 30 31 32 # 多进程的效率演示 33 # tp = ProcessPoolExecutor(5) 34 # start = time.time() 35 # for i in range(100): 36 # tp.submit(func, i) 37 # tp.shutdown() # 等效于 进程池中的 close + join 38 # print('进程池的消耗时间为%s' % (time.time() - start)) 39 40 41 42 43 # 多线程的效率 44 # tp = ThreadPoolExecutor(20) 45 # start = time.time() 46 # for i in range(1000): 47 # tp.submit(func,i) 48 # tp.shutdown()# 等效于 进程池中的 close + join 49 # print('线程池的消耗时间为%s'%(time.time() - start)) 50 51 52 # 结果:针对计算密集的程序来说 53 # 不管是Pool的进程池还是ProcessPoolExecutor()的进程池,执行效率相当 54 # ThreadPoolExecutor 的效率要差很多 55 # 所以 当计算密集时,使用多进程。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from concurrent.futures import ThreadPoolExecutor 2 import time 3 4 5 def func(num): 6 sum = 0 7 # time.sleep(5) 8 # print(num) # 异步的效果 9 for i in range(num): 10 sum += i ** 2 11 return sum 12 13 t = ThreadPoolExecutor(20) 14 15 16 # 下列代码是用map的方式提交多个任务,对应 拿结果的方法是__next__() 返回的是一个生成器对象 17 res = t.map(func,range(1000)) 18 t.shutdown() 19 print(res.__next__()) 20 print(res.__next__()) 21 print(res.__next__()) 22 print(res.__next__()) 23 24 # 下列代码是用for + submit提交多个任务的方式,对应拿结果的方法是result 25 # res_l = [] 26 # for i in range(1000): 27 # re = t.submit(func,i) 28 # res_l.append(re) 29 # # t.shutdown() 30 # [print(i.result()) for i in res_l] 31 32 # 在Pool进程池中拿结果,是用get方法。 在ThreadPoolExecutor里边拿结果是用result方法
3、回调函数
无论是ProcessPoolExecutor的进程池,还是Pool的进程池,回调函数都是父进程调用的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from concurrent.futures import ProcessPoolExecutor 2 # 不管是ProcessPoolExecutor的进程池 还是Pool的进程池,回调函数都是父进程调用的。 3 import os 4 import requests 5 6 7 def func(num): 8 sum = 0 9 for i in range(num): 10 sum += i ** 2 11 return sum 12 13 def call_back_fun(res): 14 # print(res.result(),os.getpid()) 15 print(os.getpid()) 16 17 if __name__ == '__main__': 18 print(os.getpid()) 19 t = ProcessPoolExecutor(20) 20 for i in range(1000): 21 t.submit(func,i).add_done_callback(call_back_fun) 22 t.shutdown()
4、条件
条件涉及的4个方法:
1 con.acquire() 2 con.release() 3 con.wait() # 假设有一个初始状态为False,阻塞。一旦接受到notify的信号后,变为True,不再阻塞 4 con.notify(int) 给wait发信号,发int个信号,会传递给int个wait,让int个线程正常执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from threading import Condition,Thread 2 import time 3 4 5 def func(con,i): 6 con.acquire()# 主线程和10个子线程都在抢夺递归锁的一把钥匙。 7 # 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。但是,此时如果主线程执行特别快 8 # 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号,但是因为没有拿到钥匙,所以其他子线程还是不会执行 9 con.wait() 10 print('第%s个线程执行了'%i) 11 con.release() 12 13 con = Condition() 14 for i in range(10): 15 t = Thread(target=func,args = (con,i)) 16 t.start() 17 while 1: 18 # print(123) 19 con.acquire() 20 num = input('>>>') 21 con.notify(int(num)) 22 con.release() 23 time.sleep(0.5) 24 25 # 条件 涉及 4个方法: 26 # con.acquire() 27 # con.release() 28 # con.wait() # 假设有一个初始状态为False,阻塞。一旦接受到notify的信号后,变为True,不再阻塞 29 # con.notify(int) 给wait发信号,发int个信号,会传递给int个wait,让int个线程正常执行
5、queue模块
1 from multiprocessing import Queue# 是用于多进程的队列,就是专门用来做进程间通信(IPC)。 2 import queue# 是用于同一进程内的队列,不能做多进程之间的通信 3 4 # q = queue.Queue() 5 # # 先进先出 6 # q.put(1) 7 # q.put(2) 8 # q.put(3) 9 # print(q.get()) 10 # print(q.get()) 11 12 # q = queue.LifoQueue() 13 # # 后进先出的队列 14 # q.put(1) 15 # q.put(2) 16 # q.put(3) 17 # print(q.get()) 18 19 q = queue.PriorityQueue() 20 # 优先级队列,put()方法接收的是一个元组(),第一个位置是优先级,第二个位置是数据 21 # 优先级如果是数字,直接比较数值 22 # 如果是字符串,是按照 ASCII 码比较的。当ASCII码相同时,会按照先进先出的原则 23 q.put((1,'abc')) 24 q.put((5,'qwe')) 25 q.put((-5,'zxc')) 26 print(q.get()) 27 print(q.get()) 28 print(chr(48))