python_协程
协程
问题一: 生成器与函数的区别?
生成器分阶段的返回多个值,相当于有多个出口(结果); 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_协程的更多相关文章
- python_协程方式操作数据库
# !/usr/bin/python3 # -*- coding: utf-8 -*- import requests import gevent import pymysql from gevent ...
- Python_进程、线程及协程
一.Python进程 IO密集型----多线程 计算密集型----多进程 1.单进程 from multiprocessing import Process def foo(i): print('你好 ...
- python_线程、进程和协程
线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python #coding=utf-8 __author__ = 'yinjia' i ...
- Python_多任务:进程、线程、协程
进程 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体.进程是一种抽象的概念,从来没有统一的标准定义.进程一般由程序 ...
- python_21_线程+进程+协程
python_线程_进程_协程 什么是线程? -- os能够进行运算调度的最小单位,被包含在进程之中,是一串指令的集合 -- 每个线程都是独立的,可以访问同一进程下所有的资源 什么是进程? -- 每个 ...
- Python(八)进程、线程、协程篇
本章内容: 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 线程 Threading用于提供线程相关的操作.线程是应用 ...
- Lua的协程和协程库详解
我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...
- 协程--gevent模块(单线程高并发)
先恶补一下知识点,上节回顾 上下文切换:当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另一个线程的本地数据,程序指针等,最后才开始执行.这种 ...
- Python 【第五章】:线程、进程和协程
Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python # -*- coding:utf-8 -*- import t ...
随机推荐
- NOI2019 Day2游记
开场T1是个最短路优化建图,边向二维矩形内所有点连,本来可以写树套树的,但是卡空间(128MB),后来发现其实是不用把边都建出来的,只需要用数据结构模拟dijkstra的过程,支持二维区间对一个值取m ...
- R 语言输入输出 读取命令函参数
输入数据 使用键盘输入数据 只能处理小样本,很少使用 在创建 data.txt 字符串之后,用函数 read.table() 创建数据框 data.1.这种方法可以让我们把数据嵌入到R代码中,此处切记 ...
- js浮点数精度丢失问题及如何解决js中浮点数计算不精准
js中进行数字计算时候,会出现精度误差的问题.先来看一个实例: console.log(0.1+0.2===0.3);//false console.log(0.1+0.1===0.2);//true ...
- gradle/gradle plugin/Android studio关系
gradle - 构建工具,存储于Users/stono/.gradle/wrapper/dists Adroid Studio- IDE Gradle plugin - 在AS中使用Gradle的插 ...
- 使用hdfs-mount挂载HDFS
目录 1.特性(计划)简介 2.构建程序 3.使用hdfs-mount挂载HDFS hdfs-mount是一个将HDFS挂载为本地Linux文件系统的工具,使用go语言开发,不依赖libdfs和jav ...
- GitLab的权限管理及Merge Request
GitLab的权限管理及Merge Request 原创尘世间一名迷途小码农 发布于2019-06-09 12:40:30 阅读数 2909 收藏 展开 目录 1.前言 2.角色权限 3.强制代码审 ...
- Django框架入门1虚拟开发环境的配置
1.安装virtualenv虚拟程序 C:\Users\ws>pip install virtualenv 创建名字为testvir的虚拟环境 C:\Users\ws>virtualenv ...
- 接口项目servlet的一种处理方式,将异常返回给调用者【我】
接口项目servlet的一种处理方式,其他层有异常全部网上抛,抛到servlet层,将异常返回给调用者: Servlet层: private void processRequest(HttpServl ...
- SVN中“txn-current-lock:拒绝访问”错误
SVN服务器使用的是Visual SVN,重装系统后,使用SVN commit是遇到:不能打开文件“XX:\XXXXX\db\txn-current-lock”: 拒绝访问这样的错误. 原因分析: u ...
- if [ $? -eq 0 ]的含义
if [ $? -eq 0 ]语句代表上一个命令执行后的退出状态 $0: shell或shell脚本的名字$*: 以一对双引号给出参数列表$@: 将各个参数分别加双引号返回$#: 参数 ...