一、继承、封装、多态

继承:

  • python2:深度优先继承
  • python3:广度优先继承
  • python中的继承链:继承链中保存了继承顺序,同时指明函数的执行的找到顺序
    • lion.mro()#lion的继承/执行顺序
  • 避免使用菱形继承,建议通过mixin的组合完成
  • 通过父类的方法,尽量使用super去调用。

多态:
1.子类的实例对象也是父类的实例对象(广义)

  • isinstance(cub,lion) #判断cub是不是lion的子类

2.同一类中,有同名的函数,但参数不一样,可用通过传递不同的参数,自动去调用不同的函数,这种多态是狭义上的多态,python中没有。

二、线程,进程,协程

进程:系统资源分配的最小单位
线程:系统任务调度的最小单位
协程:又叫做微线程

资源占用 数据通信 上下文切换
进程 大(M) 不方便(网络、共享内存、管道等) 操作系统按时间片切换,不够灵活,慢
线程 小(k) 非常方便 按时间片切换,不够灵活,快
协程 非常小(bytes) 非常方便 根据I/O事件切换,更加有效的利用cpu
  • 线程:from threading import Thread

    • 并行:
    • 并发:
    • GIL:全局解释锁
      多线程直接数据共享,
    • 线程安全-->加锁:
      lock=threading.lock()#创建一把锁
      lock.acquire()#加同步锁
      lock.release()#解锁
  • 进程:

    from multiprocessing import Process
    p=Process(target=foo,args=(('hot')))
    p.start()
    p.join()#阻塞

    进程之间资源不共享,解决:队列q.get(),管道obj.recv(),manager管理器

  • 进程池Pool
    当需要的子进程不多时,可用直接利用multiprocessing中的Process动态生成多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,如果创建很多进程,那么操作系统会频繁的创建和销毁进程,因为创建和销毁进程需要用到大量的资源,所以这样会消耗操作系统大量的资源。此时就可以用到multiprocessing模块提供的Pool方法,创建进程的个数是电脑核数的一倍到两倍。

  • 协程: stackless/greenlets/grvrnt/tornado/asyncio

    • 协程是运行再一个线程上的,可以理解为一个线程上可以运行多个请求,
    • 效率高于线程
      • 线程的切换操作系统要保持上下文切换的资源,
      • 协程是当进行io操作时就会自动的切换,基本不会耗费资源。
  • gevent协程

    • 创建协程

        import gevent
        def run1():
            print('a')
            gevent.sleep(2)
            print('b')
      
        def run1():
            print('a')
            gevent.sleep(1)
            print('b')
      
        if __name__ =='__main__':
            gevent.joinall([
                gevent.spawn(run1),
                gevent.spawn(run2)
                ])

由于是第三方库,它不会自动识别哪些操作时io操作,所以要在代码投加上猴子补丁

from gevent import monkey
monkey.patch_all()
- asyncio协程
import asyncio
async def run1():
    print('a')
    await asyncio.sleep(2)
    print('b')
async def run2():
    print('c')
    await asyncio.sleep(1)#await释放cpu,自己辩别改代码是否是进行io操作,若是,则需要加await#
    print('d')
if __name__ == '__main__':

    loop = asyncio.get_event_loop()#创建一个事件循环对象#
    tasks = [run2(), run1()]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

三、socket网络通信

TCP:可靠的文件传输协议
UDP:不可靠的文件传输协议

#服务端
import socket
#设置套接字
server=socket.socket()
#绑定端口号,ip
server.bind(('127.0.0.1',8888))
#设置允许连接的客户端的个数
server.listen(5)
#监听端口链接
sock,_=server.accept()
#接收数据,recv中要加上接收的字节,一般为1024
recv_data=sock.recv(1024)
#处理完之后,把数据返回给客户端
data = 'hello %s' % recv_data.decode()
sock.send(data.encode())

四、三次握手四次挥手

图片说明

为什么握手时三次,挥手却是四次?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。

而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

tcp的2MSL:

MSL:tcp报文的最大生存时间
最后一次发送响应的一端需要等待2MSL才关闭
图片说明
说明:2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,
当TCP的一端发起主动关闭,在发出最后一个ACK包后,
即第3次握 手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,
必须在此状态上停留两倍的MSL时间,
等待2MSL时间主要目的是怕最后一个 ACK包对方没收到,
那么对方在超时后将重发第三次握手的FIN包,
主动关闭端接到重发的FIN包后可以再发一个ACK应答包。
在TIME_WAIT状态 时两端的端口不能使用,要等到2MSL时间结束才可继续使用。
当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。
不过在实际应用中可以通过设置 SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

取消这个2MSL等待时间

import socket
server=socket.socket()
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)