码迷,mamicode.com
首页 > 其他好文 > 详细

协程相关

时间:2018-09-13 18:36:45      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:对象   round   .com   query   思想   object   eps   blocking   遇到   

---恢复内容开始---

思想

主要的思想:
如果一个变量自己有某种方法,而你想在不改变调用方式的前提下,希望可以点出它本身不存在的方法,就要想到用 类 封装的思想 , 将这个变量,改变为一个类的对象,在类中增加你需要的方法
例如:
# lst1= [1,2,3,4]#有append 的功能
# lst2= [1,2,3,4]#有append 的功能
# lst3= [1,2,3,4]#有append 的功能
# lst4= [1,2,3,4]#有append 的功能
# l = [lst1,lst2,lst3,lst4]
# for i in l:
# i.append(6)#很明显都可以执行,
# # i.eat() 明显直接飘红了,怎样在我不改变调用方式的前提下,可以将该功能实现:


技术分享图片
class Foo(object):
    def __init__(self,lst,eat):
        self.eat = eat
        self.lst = lst
    def append(self,n):
        print(n+1)
        self.lst.append(3)


lst1= [1,2,3,4] #有append 的功能
lst2= [1,2,3,4] #有append 的功能
lst3= [1,2,3,4] #有append 的功能
lst4= [1,2,3,4] #有append 的功能
lst1_obj = Foo(lst1,"苹果")
lst2_obj = Foo(lst2,"橘子")
lst3_obj = Foo(lst3,"xiangjiao")
lst4_obj = Foo(lst4,"jiaozi")


l = [lst1_obj,lst2_obj,lst3_obj,lst4_obj]
for i in l:
   i.append(3)#很明显都可以执行,
   print(i.eat)  #明显直接飘红了,怎样在我不改变调用方式的前提下,可以将该功能实现:
View Code
技术分享图片
# 你写的代码:7000w
                v = [
                    [11,22], # 每个都有一个append方法
                    [22,33], # 每个都有一个append方法
                    [33,44], # 每个都有一个append方法
                ]

                
                
                # 王思聪
                for item in v:
                    print(item.append)
                        
            之后:
                class Foo(object):
                    def __init__(self,data,girl):
                        self.row = data
                        self.girl = girl

                    def append(self,item):
                        self.row.append(item)

                v = [
                    Foo([11,22],雪梨), # 每个都有一个append方法
                    Foo([22,33],冰糖), # 每个都有一个append方法
                    Foo([33,44],糖宝), # 每个都有一个append方法
                ]

                for item in v:
                    print(item.append)
                    item.girl
        
View Code

 

一   IO多路复用                                                                  

1     Io多路复用的作用:监测多个socket  是否发生变化(是否已经发生成功连接,是否读取到数据)

操作系统监测socket是否发生变化,有三种模式:

select:  最多监听1024,循环监测

poll;不限制监听socket个数,还是循环监测

epoll:不限制监听个数,回调方式监测(边缘触发)

2   异步非阻塞:

              阻塞:不等待.

                     比如创建socket对某个地址 进行 connect 获取接受数据,都会默认阻塞

      如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获就行

             异步:,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。

      比如做爬虫中向某个地址baidu.com发送请求,当请求执行完成之后自执行回调函数。

3   同步   阻塞

          同步 ;按顺序执行

         阻塞:等

 

 

普通的单进程单线程

import socket
import requests

# 方式一
ret = requests.get(https://www.baidu.com/s?wd=alex)


# 方式二
client = socket.socket()

# 百度创建连接: 阻塞
client.connect((www.baidu.com,80))

# 问百度我要什么?
client.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)

# 我等着接收百度给我的回复
chunk_list = []
while True:
    chunk = client.recv(8096)
    if not chunk:
        break
    chunk_list.append(chunk)

body = b‘‘.join(chunk_list)
print(body.decode(utf-8))

解决并发----单线程

for item in key_list:
    ret = requests.get(https://www.baidu.com/s?wd=%s %item)

# 方式二
def get_data(key):
    # 方式二
    client = socket.socket()

    # 百度创建连接: 阻塞
    client.connect((www.baidu.com,80))

    # 问百度我要什么?
    client.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)

    # 我等着接收百度给我的回复
    chunk_list = []
    while True:
        chunk = client.recv(8096)
        if not chunk:
            break
        chunk_list.append(chunk)

    body = b‘‘.join(chunk_list)
    print(body.decode(utf-8))

key_list = [alex,db,sb]
for item in key_list:
    get_data(item)

解决并发-------多线程

import threading

key_list = [alex,db,sb]
for item in key_list:
    t = threading.Thread(target=get_data,args=(item,))
    t.start()

解决并发-----单线程 +io多路复用  

先了解一下setblocking

import socket

client = socket.socket()
client.setblocking(True) # 将原来阻塞的位置变成非阻塞(报错),改成 false即变成阻塞的了
# 百度创建连接: 阻塞

try:
    client.connect((www.baidu.com,80)) # 执行了但报错了
except BlockingIOError as e:
    pass

# 检测到已经连接成功

# 问百度我要什么?
client.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)

# 我等着接收百度给我的回复
chunk_list = []
while True:
    chunk = client.recv(8096) # 将原来阻塞的位置变成非阻塞(报错)
    if not chunk:
        break
    chunk_list.append(chunk)

body = b‘‘.join(chunk_list)
print(body.decode(utf-8))

普通版本---单线程  +io      基于事件循环实现的异步非阻塞框架

import socket
import select



client1 = socket.socket()
client1.setblocking(False) # 百度创建连接: 非阻塞

try:
    client1.connect((www.baidu.com,80))
except BlockingIOError as e:
    pass


client2 = socket.socket()
client2.setblocking(False) # 百度创建连接: 非阻塞
try:
    client2.connect((www.sogou.com,80))
except BlockingIOError as e:
    pass


client3 = socket.socket()
client3.setblocking(False) # 百度创建连接: 非阻塞
try:
    client3.connect((www.oldboyedu.com,80))
except BlockingIOError as e:
    pass

socket_list = [client1,client2,client3]
conn_list = [client1,client2,client3]

while True:
    rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005)
    # wlist中表示已经连接成功的socket对象
    for sk in wlist:
        if sk == client1:
            sk.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
        elif sk==client2:
            sk.sendall(bGET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n)
        else:
            sk.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n)
        conn_list.remove(sk)
    for sk in rlist:
        chunk_list = []
        while True:
            try:
                chunk = sk.recv(8096)
                if not chunk:
                    break
                chunk_list.append(chunk)
            except BlockingIOError as e:
                break
        body = b‘‘.join(chunk_list)
        # print(body.decode(‘utf-8‘))
        print(------------>,body)
        sk.close()
        socket_list.remove(sk)
    if not socket_list:
        break

高级版本的   并发 -----单线程+Io

import socket
import select

class Req(object):
    def __init__(self,sk,func):
        self.sock = sk
        self.func = func

    def fileno(self):
        return self.sock.fileno()


class Nb(object):

    def __init__(self):
        self.conn_list = []
        self.socket_list = []

    def add(self,url,func):
        client = socket.socket()
        client.setblocking(False)  # 非阻塞
        try:
            client.connect((url, 80))
        except BlockingIOError as e:
            pass
        obj = Req(client,func)
        self.conn_list.append(obj)
        self.socket_list.append(obj)

    def run(self):

        while True:
            rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005)
            # wlist中表示已经连接成功的req对象
            for sk in wlist:
                # 发生变换的req对象
                sk.sock.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
                self.conn_list.remove(sk)
            for sk in rlist:
                chunk_list = []
                while True:
                    try:
                        chunk = sk.sock.recv(8096)
                        if not chunk:
                            break
                        chunk_list.append(chunk)
                    except BlockingIOError as e:
                        break
                body = b‘‘.join(chunk_list)
                # print(body.decode(‘utf-8‘))
                sk.func(body)
                sk.sock.close()
                self.socket_list.remove(sk)
            if not self.socket_list:
                break


def baidu_repsonse(body):
    print(百度下载结果:,body)

def sogou_repsonse(body):
    print(搜狗下载结果:, body)

def oldboyedu_repsonse(body):
    print(老男孩下载结果:, body)


t1 = Nb()
t1.add(www.baidu.com,baidu_repsonse)
t1.add(www.sogou.com,sogou_repsonse)
t1.add(www.oldboyedu.com,oldboyedu_repsonse)
t1.run()

 二  协程   协程不是真实存在的  是程序员为了提高并发效率,开创的

技术分享图片
 协程 
        
            进程,操作系统中存在;
            线程,操作系统中存在;
            协程,是由程序员创造出来的一个不是真实存在的东西;
        
        协程:是微线程,对一个线程进程分片,使得线程在代码块之间进行来回切换执行,而不是在原来逐行执行。
        
        注意:单纯的协程无用
                
        协程 + 遇到IO就切换 => 牛逼起来了  pip3 install gevent 
        
            
            
        总结:
            1. 什么是协程?
                协程也可以称为“微线程”,就是开发者控制线程执行流程,控制先执行某段代码然后再切换到另外函执行代码...来回切换。
            
            2. 协程可以提高并发吗?
                协程自己本身无法实现并发(甚至性能会降低)。
                协程+IO切换性能提高。
                
            3. 进程、线程、协程的区别?
                
            4. 单线程提供并发:
                - 协程+IO切换:gevent
                - 基于事件循环的异步非阻塞框架:Twisted
            
协程定义
技术分享图片
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()
greenlet
技术分享图片
from gevent import monkey
monkey.patch_all() # 以后代码中遇到IO都会自动执行greenlet的switch进行切换
import requests
import gevent


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/), # 协程1
    gevent.spawn(get_page2, https://www.yahoo.com/),  # 协程2
    gevent.spawn(get_page3, https://github.com/),     # 协程3
])
gevent
技术分享图片
def f1():
    print(11)
    yield
    print(22)
    yield
    print(33)

def f2():
    print(55)
    yield
    print(66)
    yield
    print(77)

v1 = f1()
v2 = f2()

next(v1) # v1.send(None)
next(v2) # v1.send(None)
next(v1) # v1.send(None)
next(v2) # v1.send(None)
next(v1) # v1.send(None)
next(v2) # v1.send(None)
yield 实现的协程
技术分享图片
import socket
import select

class Req(object):
    def __init__(self,sk,func):
        self.sock = sk
        self.func = func

    def fileno(self):
        return self.sock.fileno()


class Nb(object):

    def __init__(self):
        self.conn_list = []
        self.socket_list = []

    def add(self,url,func):
        client = socket.socket()
        client.setblocking(False)  # 非阻塞
        try:
            client.connect((url, 80))
        except BlockingIOError as e:
            pass
        obj = Req(client,func)
        self.conn_list.append(obj)
        self.socket_list.append(obj)

    def run(self):

        while True:
            rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005)
            # wlist中表示已经连接成功的req对象
            for sk in wlist:
                # 发生变换的req对象
                sk.sock.sendall(bGET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
                self.conn_list.remove(sk)
            for sk in rlist:
                chunk_list = []
                while True:
                    try:
                        chunk = sk.sock.recv(8096)
                        if not chunk:
                            break
                        chunk_list.append(chunk)
                    except BlockingIOError as e:
                        break
                body = b‘‘.join(chunk_list)
                # print(body.decode(‘utf-8‘))
                sk.func(body)
                sk.sock.close()
                self.socket_list.remove(sk)
            if not self.socket_list:
                break
基于事件循环的异步非阻塞自己写的 ---名字叫 emma---
技术分享图片
from emma import Nb

def baidu_repsonse(body):
    print(百度下载结果:,body)

def sogou_repsonse(body):
    print(搜狗下载结果:, body)

def oldboyedu_repsonse(body):
    print(老男孩下载结果:, body)


t1 = Nb()
t1.add(www.baidu.com,baidu_repsonse)
t1.add(www.sogou.com,sogou_repsonse)
t1.add(www.oldboyedu.com,oldboyedu_repsonse)
t1.run()
使用 emma

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢复内容结束---

协程相关

标签:对象   round   .com   query   思想   object   eps   blocking   遇到   

原文地址:https://www.cnblogs.com/lxx7/p/9642051.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!