协程相关

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

思想

主要的思想:如果一个变量自己有某种方法,而你想在不改变调用方式的前提下,希望可以点出它本身不存在的方法,就要想到用  类  封装的思想 , 将这个变量,改变为一个类的对象,在类中增加你需要的方法例如:
# 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)  #明显直接飘红了,怎样在我不改变调用方式的前提下,可以将该功能实现:

# 你写的代码: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
        

一   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(b‘GET /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(b‘GET /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(b‘GET /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(b‘GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n‘)
        elif sk==client2:
            sk.sendall(b‘GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n‘)
        else:
            sk.sendall(b‘GET /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(b‘GET /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(b‘GET /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

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

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

时间: 2024-09-30 22:46:26

协程相关的相关文章

Python3 协程相关

什么是协程 协程的优势 Python3中的协程 生成器 yield/send yield + send(利用生成器实现协程) 协程的四个状态 协程终止 @asyncio.coroutine和yield from asyncio.coroutione yield from 为什么要用yield from async/await关键字 什么是协程 ??协程(Coroutine),又称微线程,纤程.通常我们认为线程是轻量级的进程,因此我们也把协程理解为轻量级的线程即微线程. ??协程的作用是在执行函数

Python学习经验之谈:关于协程的理解和其相关面试问题

都知道Python非常适合初学者学习来入门编程,昨天有伙伴留言说面试了Python岗位,问及了一个关于协程的问题,想了想还是跟大家出一篇协程相关的文章和在Python面试中可能会问及的相关面试问题.都是根据我自己的Python学习经验来写的,有这方面需求的伙伴可以认真阅读,也欢迎补充不足之处! 一.什么是协程 协程:实现协作式多任务,可以在程序执行内部中断,转而执行其他协程. 比如我们编写子程序(或者说函数),通常是利用“调用”来实现从 A 跳去 B,B 跳去 C,如果想回来调用方,必须等被调用

协程初探

文章出处:http://blog.csdn.net/lanphaday/archive/2010/03/19/5397038.aspx 协程,又称微线程和纤程等,据说源于 Simula 和 Modula-2 语言(我没有深究,有错请指正),现代编程语言基本上都有支持,比方 Lua.ruby 和最新的 Google Go,当然也还有近期非常让我惊艳的 falcon.协程是用户空间线程,操作系统对其存在一无所知,所以须要用户自己去做调度,用来运行协作式多任务非常合适.其有用协程来做的东西,用线程或进

 PHP_Yield协程从入门到精通

本文和大家分享的主要是PHP中Yield协程相关内容,一起来看看吧,希望对大家学习php有所帮助. 协程 基本概念 "协程"(Coroutine)概念最早由 Melvin Conway 于1958年提出.协程可以理解为纯用户态的线程,其通过协作而不是抢占来进行切换.相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低.总的来说,协程为协同任务提供了一种运行时抽象,这种抽象非常适合于协同多任务调度和数据流处理.在现代操作系统和编程语言中,因为用户态线程切换代价比内核

协程Coroutine

协程是一种用户态的轻量级线程. server的发展如下: IO密集型应用: 多进程->多线程->事件驱动->协程 CPU密集型应用:多进程-->多线程 如果说多进程对于多CPU,多线程对应多核CPU,那么事件驱动和协程则是在充分挖掘不断提高性能的单核CPU的潜力. 异步事件驱动模型中,把会导致阻塞的操作转化为一个异步操作,主线程负责发起这个异步操作,并处理这个异步操作的结果.由于所有阻塞的操作都转化为异步操作,理论上主线程的大部分时间都是在处理实际的计算任务,少了多线程的调度时间,

Lua 协程 coroutine

协程是协同程序的简称,顾名思义,就是协同工作的程序.协程拥有自己独立的桟.局部变量和PC计数器,同时又与其他协同程序共享全局变量和其他大部分东西: 协程与线程的主要区别在于,一个多线程程序可以同时运行几个线程(并发执行.抢占),而协同程序却需要彼此协作地运行,即一个多协程程序在任意时刻只能运行一个协程,并且正在执行的协程只会在其显式地要求挂起(suspend)时,它的执行才会暂停(无抢占.无并发). Lua中所有与协程相关的函数都在coroutine(一个table)中: 函数create用于创

进程、线程和协程的理解-自己随笔

1. IO 操作不占用CPU(从硬盘读数据,从网络读数据,从内存读取数据) 计算占用CPU,例如1+1=2的计算就是占用CPU的. python 多线程,不适合CPU密集操作系统的任务,适合IO操作密集型的任务. 2. 进程.线程和协程之间的关系和区别也困扰我一阵子了,最近有一些心得,写一下. 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的). 协程和线程一样共享堆,不共享栈,协程由程序

从Erlang进程看协程思想

从Erlang进程看协程思想 多核慢慢火了以后,协程类编程也开始越来越火了.比较有代表性的有Go的goroutine.Erlang的Erlang进程.Scala的actor.windows下的fibre(纤程)等,一些动态语言像Python.Ruby.Lua也慢慢支持协程. 其实我们听过协程相关很多名词,下面大致来解释一下: OS进程: 进程是资源管理的最小单元,包括进程控制块(PCB).程序段.数据段 OS线程: 线程是程序执行的最小单元,由线程ID,当前指令指针(PC),寄存器集合和堆栈组成

[转载]协程-cooperative multitasking

[转载]协程三讲 http://ravenw.com/blog/2011/08/24/coroutine-part-1-defination-and-classification-of-coroutine/ http://ravenw.com/blog/2011/09/01/coroutine-part-2-the-use-of-coroutines/ http://ravenw.com/blog/2011/09/06/coroutine-part-3-coroutine-and-continu