python中IO多路复用、协程

一、IO多路复用
    IO多路复用:检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写)

import socket
def get_data(key):
    client = socket.socket()
    client.setblocking(False)   #将原阻塞的位置变成非阻塞
    try:
        client.connect(("www.baidu.com",80))    #因为没有等待所以会报错
    except BlockingIOError as e:
        pass
    client.sendall(b"GET /s?wd=%s HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n" %key)
    data_list = []
    while 1:
        data = client.recv(8096)
        if not data:
            break
        data_list.append(data)
    data = b"".join(data_list)
    print(data.decode("utf8"))
key_list = ["alex","sb","db"]
for item in key_list:
    get_data(item)
View Code

二、基于IO多路复用+socket实现并发请求
  IO多路复用
  socket非阻塞
  基于事件循环实现的异步非阻塞框架
    非阻塞:不等待
    异步:执行完某个人物后自动调用我给他的函数。
      Python中开源 基于事件循环实现的异步非阻塞框架 Twisted

    总结:
      1. socket默认是否是阻塞的?阻塞体现在哪里?
          是,connect、accept、recv
      2. 如何让socket编程非阻塞?
          setblocking(False)
      3. IO多路复用作用?
        检测多个socket是否发生变化。
        操作系统检测socket是否发生变化,有三种模式:
          select:最多1024个socket;循环去检测。
          poll:不限制监听socket个数;循环去检测(水平触发)。
          epoll:不限制监听socket个数;回调方式(边缘触发)。
        Python模块:
          select.select
          select.epoll

      4. 提高并发方案:
        - 多进程
        - 多线程
        - 异步非阻塞模块(Twisted) scrapy框架(单线程完成并发)

      5. 什么是异步非阻塞?
        - 非阻塞,不等待。
          比如创建socket对某个地址进行connect、获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作。
          如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获即可。
        - 异步,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。

      6. 什么是同步阻塞?
        - 阻塞:等
        - 同步:按照顺序逐步执行
        key_list = ['alex','db','sb']
        for item in key_list:
          ret = requests.get('https://www.baidu.com/s?wd=%s' %item)
          print(ret.text)

      7.概念 

#以前
v = [[11,22],[33,44],[55,66]] #每一个都有一个append方法
for item in v:
    print(item.append(1))
#以后
class Foo(object):
    def __init__(self,data):
        self.data = data
    def append(self,ietm):
        self.data.appded(item)
v = [[11,22],[33,44],[55,66]]
for item in v:
    print(item.append(1))
面向对象的思想

三、协程

    概念:

      进程、操作系统中存在

      线程、操作系统中存在

      协程、是由程序员创造出来的一个不是真实存在的东西

  协程:是微线程,是对一个线程进行分片,使得线程在代码块之间来回切回执行,而不是在原来逐行执行

import greenlet
def f1():
    print(11)
    gr2.switch()
    print(22)
    gr2.switch()
def f2():
    print(33)
    gr1.switch()
    print(44)
#协程gr1
gr1 = greenlet.greenlet(f1)
#协程gr2
gr2 = greenlet.greenlet(f2)
gr1.switch()
View Code

  注:单纯用协程无用

  协程+遇到IO就切换,才真的有用  pip3 install gevent

import gevent
from gevent import monkey
monkey.patch_all()
import requests
def get_page1(url):
    ret = requests.get(url)
    print(url,ret.content)
def get_page2(url):
    ret = requests.get(url)
    print(url,ret.content)
def get_page3(url):
    ret = requests.get(url)
    print(url,ret.content)
gevent.joinall([gevent.spawn(get_page1, 'https://www.python.org/'),
                gevent.spawn(get_page2, 'https://www.yahoo.com/'),
                gevent.spawn(get_page3, 'https://github.com/')
                ])
View Code

  总结:

    1什么是协程:

      协程也可以成为微线程,基石开发者控制线程执行流程,控制先执行某段代码然后在切换到另外函数执行代码

    2.协程可以提高并发么

      协程自己本身无法实现并发(甚至性能会降低)

      协程+IO切换性能提高

    3.进程、线程、协程的区别

    4.单线程提高并发:

      协程+IO切换:gevent

      基于事件循环的异步非阻塞框架:Twisted

twisted

from twisted.web.client import getPage, defer
from twisted.internet import reactor

def all_done(arg):
    reactor.stop()

def callback(contents):
    print(contents)

deferred_list = []
url_list = ['http://www.bing.com', 'http://www.baidu.com', ]
for url in url_list:
    deferred = getPage(bytes(url, encoding='utf8'))
    deferred.addCallback(callback)
    deferred_list.append(deferred)

dlist = defer.DeferredList(deferred_list)
dlist.addBoth(all_done)

reactor.run()
View Code

 

posted @ 2018-09-13 17:04  被嫌弃的胖子  阅读(303)  评论(0编辑  收藏  举报