协程

问题一: 生成器与函数的区别?
生成器分阶段的返回多个值,相当于有多个出口(结果); yield

'''
yield # 中断、返回函数值
1、只能在函数中使用
2、会暂停函数执行并且返回表达式结果
3、一次只能返回一个值 yield 取值
next()
'''
def func():
print(1)
yield 'a'
print(2)
yield 'b'
print(3) g = func()
print(next(g))
g.__next__()

问题二: 协程与生成器的区别?
有多个出口,同时可以有多个入口

def func():
a = (yield )
print(a)
b = (yield )
print(b)
# c = (yield )
# print(c) g = func()
g.send(None) # 第一次发送必须是None 或者使用 next(g) 对应的 a,发送的是个空
print(g.send(1)) # 对应的是b
print(g.send(2)) # 到这里就停止了。 StopIteration, 因为后面没有了

问题三: 协程算并发嘛?
严格来说 不算。如果有一个地方卡住了, 会一直卡
问题四: 协程的意义?
最主要"配合io多路复用使用",当前的意义就是切换使用,耗费资源小

生产者/消费者模型

import random, time

# 生产者
def produce(consumer): # 参数(生成器)
next(consumer)
while True:
item = random.randint(0, 99) # 随机生成一个数
print("生产者生产了%s" % item)
consumer.send(item) # 把item给消费者
time.sleep(2) def consumer(): # 消费者 才是一个协程(生成器)
while True:
item = (yield )
print("消费者消费了%s " % item) c = consumer()
produce(c)

greenlet

问题一: 什么是greenlet ?
虽然CPython(标准Python)能够通过生成器来实现协程,

但使用起来还并不是很方便。

与此同时,Python的一个衍生版 Stackless Python

实现了原生的协程,它更利于使用。

于是,大家开始将 Stackless 中关于协程的代码
单独拿出来做成了CPython的扩展包。

这就是 greenlet 的由来,因此 greenlet 是底层实现了原生协程的 C扩展库。
说白了就是协程
问题二: 如何使用 greenlet ?

from greenlet import greenlet
import random, time # 生产者
def produce(): # 参数(生成器)
while True:
item = random.randint(0, 99) # 随机生成一个数
print("生产者生产了%s" % item)
c.switch(item) # 切换到消费者,并将item传入消费者
time.sleep(2) def consumer(): # 消费者 才是一个协程(生成器)
while True:
item = p.switch() # 切换到消费者,并等待消费者传入item
print("消费者消费了%s " % item) p = greenlet(produce) # 把函数包装成一个协程
c = greenlet(consumer)
c.switch() # 启动

问题三: 为什么需要greenlet ?
greenlet 的价值
  价值一: 高性能的原生协程
  价值二: 语义更加明确的显式切换
  价值二: 语义更加明确的显式切换

gevent协程

问题一: 什么是 gevent ?

sudo pip3 install gevent

虽然,我们有了 基于 epoll 的回调式编程模式,但是却难以使用。

即使我们可以通过配合 生成器协程 进行复杂的封装,以简化编程难度。 但是仍然有一个大的问题: 封装难度大,现有代码几乎完全要重写

gevent,通过封装了 libev(基于epoll) 和 greenlet 两个库。 帮我们做好封装,允许我们以类似于线程的方式使用协程。

以至于我们几乎不用重写原来的代码就能充分利用 epoll 和 协程 威力。

问题二: gevent 的价值是什么 ?
遇到阻塞就切换到
另一个协程继续执行 !

价值一: 使用基于 epoll 的 libev 来避开阻塞

价值二: 使用基于 gevent 的 高效协程 来切换执行
价值三: 只在遇到阻塞的时候切换,
没有轮需的开销,也没有线程的开销

问题三: 如何使用 gevent ?
g
e
v
e
n
t





from gevent import monkey;monkey.patch_socket()

import gevent
import socket server = socket.socket()
server.bind(('0.0.0.0', 8888))
server.listen(1000) def workon(conn):
while True:
data = conn.recv(1024)
if data:
print(data.decode())
conn.send(data) else:
conn.close()
break
while True:
conn, addr = server.accept()
# Thread(target=workon, args=(conn,)).start() # 多线程的方法
gevent.spawn(workon, conn)

gevent 协程通信

gevent通信 问题引入
问题一: 协程之间不是能通过switch通信嘛?

是的,由于 gevent 基于 greenlet,所以可以。

问题二: 那为什么还要考虑通信问题?
因为 gevent 不需要我们使用手动切换,
而是遇到阻塞就切换,因此我们不会去使用switch !

gevent.queue.Queue
from gevent import monkey;monkey.patch_all()
import gevent
from gevent.queue import Queue
import random
'''
gevent.queue.Queue
'''
q = Queue(3)
# 生产者
def produce(q):
while True:
item = random.randint(0, 99)
print("生产者生产了%s" % item)
q.put(item)
gevent.sleep(1) def consumer(q):
while True:
item = q.get()
print("消费者消费了%s" % item)
gevent.sleep(1) p = gevent.spawn(produce, q) # 将函数封装成协程,并开始调度
c = gevent.spawn(consumer, q)
# c.switch() # 开启(不使用) gevent.joinall([p, c]) # 阻塞(一阻塞就切换协程)等待

测试用客户端:

import socket

client = socket.socket()                    #创建一个套接字
client.connect( ('127.0.0.1',8888 ) ) #连接服务端 while True:
data = input('请输入你要发送的数据:') data = data.encode() client.send(data)
print('接收到的数据:', client.recv(1024).decode())

协程整理完毕。

作者:含笑半步颠√

博客链接:https://www.cnblogs.com/lixy-88428977

声明:本文为博主学习感悟总结,水平有限,如果不当,欢迎指正。如果您认为还不错,欢迎转载。转载与引用请注明作者及出处。

python_协程的更多相关文章

  1. python_协程方式操作数据库

    # !/usr/bin/python3 # -*- coding: utf-8 -*- import requests import gevent import pymysql from gevent ...

  2. Python_进程、线程及协程

    一.Python进程 IO密集型----多线程 计算密集型----多进程 1.单进程 from multiprocessing import Process def foo(i): print('你好 ...

  3. python_线程、进程和协程

    线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python #coding=utf-8 __author__ = 'yinjia' i ...

  4. Python_多任务:进程、线程、协程

    进程 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体.进程是一种抽象的概念,从来没有统一的标准定义.进程一般由程序 ...

  5. python_21_线程+进程+协程

    python_线程_进程_协程 什么是线程? -- os能够进行运算调度的最小单位,被包含在进程之中,是一串指令的集合 -- 每个线程都是独立的,可以访问同一进程下所有的资源 什么是进程? -- 每个 ...

  6. Python(八)进程、线程、协程篇

    本章内容: 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 线程 Threading用于提供线程相关的操作.线程是应用 ...

  7. Lua的协程和协程库详解

    我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...

  8. 协程--gevent模块(单线程高并发)

    先恶补一下知识点,上节回顾 上下文切换:当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执行.这种 ...

  9. Python 【第五章】:线程、进程和协程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python # -*- coding:utf-8 -*- import t ...

随机推荐

  1. P3386 【模板】二分图匹配(匈牙利算法)

    题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 ...

  2. nginx.conf 配置解析之文件结构

    nginx.conf配置文件结构如下: ...... #主要定义nginx的全局配置 events{ #events(事件)块:主要配置网络连接相关 } http{ #http块:代理缓存和日志定义绝 ...

  3. python 脚本接受参数

    import os import sys print(sys.argv) bogon:Desktop macname$ python3 test2.py deesws.json dede.json s ...

  4. Dice Similarity Coefficent vs. IoU Dice系数和IoU

    Dice Similarity Coefficent vs. IoU Several readers emailed regarding the segmentation performance of ...

  5. K8S集群搭建——基于CentOS 7系统

    环境准备集群数量此次使用3台CentOS 7系列机器,分别为7.3,7.4,7.5 节点名称 节点IPmaster 192.168.0.100node1 192.168.0.101node2 192. ...

  6. OpenFOAM——圆筒壁稳态导热

    对于圆筒壁的稳态导热,温度分布的解析解为: IN为恒温边界,设置为300K,OUT也为恒温边界,设置为500K 固体导热系数为:0.0887W/(m·K) 首先进行建模操作,任何建模软件均可,本算例采 ...

  7. 在Asp.Net Core 3.0中如何使用 Newtonsoft.Json 库序列化数据

    在.Net Core 3.0中 内置了一套Json序列化/反序列化方案,默认可以不再依赖,不再支持   Newtonsoft.Json. 但是.NET Core 3.0 System.Text.Jso ...

  8. win10 安装mysql 8.0.18 解决Navicat初次连接报错

    win10 安装mysql 8.0.18 解决Navicat初次连接报错 win10 安装mysql 8.0.18-winx64 一,先去官网下载mysql 安装包 https://dev.mysql ...

  9. MySQL应用报错:java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction

    开发反馈,某业务系统插入一条记录的时候,日志报错,插入失败: ### Error updating database. Cause: java.sql.SQLException: Lock wait ...

  10. Running MYSQL 5.7 By Bash On Ubuntu On Windows:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

    root@PC-RENGUOQIANG:/usr/sbin# /etc/init.d/mysql start * Starting MySQL database server mysqld [ OK ...