学无止境

少年辛苦终身事,莫向光阴惰寸功。——唐·杜荀鹤《题弟侄书堂》


网络-并发服务器

单进程tcp服务器

  • SOCK_STREAM tcp服务器
  • bind绑定端口号
  • 设置正常情况推出的服务器下端口可以重用
  • socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    
  • accept() 阻塞 socket.accept()
  • sever_socket.setblocking(False) #设置false不阻塞当前accept()不会阻塞
  • 但是没有客户端访问的时候就会报错
  • 由客户端不会报错
  • #设置正常情况退出的服务器下,端口可以重用
  • server_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)设置再bind后面
  • 接收数据recv
  • new_socket.setblocking(False)设置recv不阻塞
  • recv是一个阻塞方法
  • 单进程tcp服务器就是阻塞服务器
  • setblocking(FALSE)设置不阻塞


单进程tcp服务器-非阻塞模式


单进程tcp服务器select版

  • select返回的是列表
  • select.select()unix底层筛选功能,得到有请求的服务器并返回到一个列表然后遍历这个列表得到请求的数据
  • import sys
    
  • sys.stdin #读取键盘内容 输入流in--->read
    
  • sys.stdout #out  --->write
    
  • sys.stderr 
    

  • poll解决套接字上线的问题
  • poll解决了套接字有上限的问题,效率和select一样,都是轮询方式。
  • select –>最多1024个套接字–>采用轮询方式进程检测套接字是否可以接收等
  • poll –>解决了支持套接字上线问题–>采用轮询方式进程检测
  • epoll–>解决支持上限问题–>采用的是事件通知

单进程tcp服务器-epoll版


  • select 和poll都是轮询检测方式,效率比较低,epoll采用的事件通知机制,这个时候epoll效率原高于select和poll
  • epoll的优点
  • 没有最大并发链接的限制,能打开的FD(指的是文件描述符,通俗的理解就是套接字对应的数字编号)的上限远大于1024
  • 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降,只有活跃可用的FD才会调用callback函数,即epoll最大的有点就在于它只管你“活跃”的链接,而跟链接总数无关,因此再世纪的网络环境中,epoll的小康v就会远远高于select和poll
  • epoll采用的是事件通知机制
  • 文件描述符:
  • linux内核(kernel)利用文件描述符(file descriptor)来访问文件
  • 文件描述符是非负整数
  • 文件描述符在形式上是一个非负整数
  • 实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表
  • 但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。Window没有
  • sys.stdin.fileno()
  • 习惯上,标准输入(standard input)的文件描述符是 0
  • sys.stdout.fileno()
  • 标准输出(standard output)是 1
  • sys.stderr.fileno()
  • 标准错误(standard error)是 2
  • 新建立的文件都有文件描述符

  • 多任务实现–协程


  • 协程,又程微线程,纤程,英文名:coroutine
  • 而协程的操作则是程序员指定的,在python中通过yield,人为的实现并发处理。
  • 协程存在的意义:
  • 协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。
  • 协程的应用场景:当程序中存在大量不需要CPU的操作时(IO)。
  • 首先我们得知道协程是啥?协程其实比线程更小的执行单元。 为啥说他是一个执行单元,因为他自带CPU上下文。
  • 协程和线程差异:
  • 线程切换非常耗性能
  • 但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
  • 协程的问题-协程程序员自己调度
  • 让需要执行的协程更多的获得CPU时间才是问题的关键。
  • 计算密集型和IO密集型

  • 计算密集型–>例如for循环里嵌套10层for循环–>占大量的cpu资源–>解决方案–>使用多进程不能用多线程(多线程中有个全局锁GIL)
  • IO密集型->需要网络功能,大量的事件等待网络数据的到来–>多线程、协成
  • 尽量不要再协程里面做IO密集型操作