关于协程

协程 coroutine 微线程,一种用户态的轻量级线程

好处:
无需线程上下文切换的开销
无需原子操作锁定及同步的开销
方便切换控制流,简化编程模型
高并发+高扩展+低成本,一个cup支持上万的协程都不是问题

缺点:
无法利用多核资源,协程的本质是单线程,
进程阻塞blocking操作如io时会阻塞整个程序

单线程下实现并发效果:遇到io就切换

服务器处理模型:
1.一个进程处理一个请求
2.一个线程处理一个请求
3.主进程处理事件队列的请求

事件驱动模型:
多个事件 -> 消息队列 -> 处理线程

事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。
它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。
另外两种常见的编程范式是(单线程)同步以及多线程编程。

异步asynchronous

用户空间application 和 内核空间kernel
进程控制块(Processing Control Block)

参考:
http://www.cnblogs.com/alex3714/articles/5876749.html

io操作两个阶段:内核缓冲区数据准备,拷贝到应用程序地址空间

阻塞io blocking 一直等待
非阻塞io nonblocking 准备数据立刻返回
多路复用 select,poll,epoll
异步io 没有被阻塞

twisted框架

手动切换协程

from greenlet import greenletdef foo1():print("foo11")gr2.switch()print("foo12")gr2.switch()def foo2():print("foo21")gr1.switch()print("foo22")gr1 = greenlet(foo1)  # 创建协程
gr2 = greenlet(foo2)print("main")gr1.switch()  # 切换协程print("done")
"""
main
foo11
foo21
foo12
foo22
done
"""

自动切换协程

import gevent  # 第三方库def foo1():print("foo11")gevent.sleep(2)print("foo12")def foo2():print("foo21")gevent.sleep(2)print("foo22")def foo3():print("foo31")gevent.sleep(0)print("foo32")gevent.joinall([gevent.spawn(foo1),gevent.spawn(foo2),gevent.spawn(foo3)
])"""
foo11
foo21
foo31
foo32
foo12
foo22
"""

gevent 多并发socket

import socket
import gevent
from gevent import monkeymonkey.patch_all()  # 猴子补丁def server(port):s = socket.socket()s.bind(("0.0.0.0", port))s.listen(500)print("服务已启动")while True:conn, addr = s.accept()print(addr)gevent.spawn(handle_request, conn)def handle_request(conn): # 处理请求的协程try:while True:data = conn.recv(1024)print(conn, data.decode())conn.send(data)if not data:conn.shutdown(socket.SHUT_WR)except Exception as e:print(e)finally:print("关闭", conn)conn.close()if __name__ == "__main__":server(6969)

select 多并发socket

# fd  文件描述符import select
import socket
import queueserver = socket.socket()server.setblocking(False)  # 不阻塞server.bind(("localhost", 6969))
server.listen(5)
print("服务已开启")inputs = [server, ]  # server本身也是一个文件描述符
outputs = []message_dict = {}while True:# 如果没有任何 fd 就绪,就会阻塞在这里readable, writeable, exceptional = select.select(inputs, outputs, inputs)print("readable", readable)print("writeable", writeable)print("exceptional", exceptional)for r in readable:if r is server:  # server就绪,新连接来了conn, addr = r.accept()print("已连接", conn)conn.setblocking(False)inputs.append(conn)  # 为了不阻塞程序,收到连接对象后放入列表,如果接收到信息,fd就绪message_dict[conn] = queue.Queue()  # 新建消息队列,不立刻返回,逐个处理else:  # 如果不是服务器,就是客户端data = r.recv(1024)if not data:print("连接断开")else:print("收到数据", data.decode("utf-8"))message_dict[r].put(data)  # 放入消息队列outputs.append(r)  # 不影响其他客户端连接,后续处理发送信息for s in outputs:  # 要返回给客户端的连接表data = message_dict[s].get()s.send(data)outputs.remove(s)  # 处理完就删除for e in exceptional:  # 删除异常连接if e in outputs:outputs.remove(e)inputs.remove(e)del message_dict[e]

selectors 多并发socket

import selectors
import socketdef accept(server, mask):  # 接受连接conn, addr = server.accept()print("conn:", conn, "addr:", addr, "mask:", mask)conn.setblocking(False)selector.register(conn, selectors.EVENT_READ, action)def action(conn, mask):  # 接收数据data = conn.recv(1024)if data:print("conn:", conn, "data:", data.decode("utf-8"))conn.send(data)else:print("断开连接")conn.close()selector.unregister(conn)server = socket.socket()
server.setblocking(False)
address = ("localhost", 6969)
server.bind(address)
server.listen(1000)selector = selectors.DefaultSelector()
selector.register(server, selectors.EVENT_READ, accept)  # accept回调函数
print("服务启动")while True:events = selector.select()  # 默认阻塞,有活动则返回活动列表for key, mask in events:callback = key.data  # acceptcallback(key.fileobj, mask)  # fileobj 文件句柄

异步爬虫(并行)

from urllib import request
from gevent import monkey
import time, geventmonkey.patch_all()  # 把当前程序所有io操作都做上标记def get_html(url):response = request.urlopen(url)html = response.read()print("receive:", len(html))urls = ["https://www.python.org/","https://www.yahoo.com/","https://github.com/"]start_time = time.time()for url in urls:html = get_html(url)end_time = time.time()print("串行:", end_time - start_time)async_start_time = time.time()gevent.joinall([gevent.spawn(get_html, urls[0]),gevent.spawn(get_html, urls[1]),gevent.spawn(get_html, urls[2])
])async_end_time = time.time()print("并行:", async_end_time - async_start_time)"""
receive: 48893
receive: 511654
receive: 52225
串行: 4.339118003845215
receive: 48893
receive: 502566
receive: 52223
并行: 1.4489901065826416
"""

Python编程:协程coroutine相关推荐

  1. 并发编程协程(Coroutine)之Gevent

    并发编程协程之Gevent Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate r ...

  2. python3 协程 写法_理解Python的协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

  3. 理解Python的协程(Coroutine)

    生成器(Generator) yield表达式的使用 生产者和消费者模型 yield from表达式 协程(Coroutine) @asyncio.coroutine async/await 总结 参 ...

  4. c++ 协程_理解Python协程(Coroutine)

    由于GIL的存在,导致Python多线程性能甚至比单线程更糟. GIL: 全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种 ...

  5. Python基础入门教程:使用 Python 3 协程快速获得一个代理池

    Python基础入门教程:使用 Python 3 协程快速获得一个代理池 前言 在执行 IO 密集型任务的时候,程序会因为等待 IO 而阻塞.比如我们使用 requests 库来进行网络爬虫请求的话, ...

  6. python中协程与函数的区别_深入浅析python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

  7. python进程\协程\异步IO

    进程 学习python中有什么不懂的地方,小编这里推荐加小编的python学习群:895 817 687有任何不懂的都可以在里面交流,还有很好的视频教程pdf学习资料,大家一起学习交流! Python ...

  8. python异步和进程_12.python进程\协程\异步IO

    进程 Python中的多线程无法利用多核优势 , 所以如果我们想要充分地使用多核CPU的资源 , 那么就只能靠多进程了 multiprocessing模块中提供了Process , Queue , P ...

  9. python中协程与函数的区别_python 协程与go协程的区别

    进程.线程和协程 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定义: 操作系统能够进行运算调度的最小单位.它被包含在进 ...

最新文章

  1. batchelor包去除单细胞RNA-seq数据批次效应
  2. 鸽巢原理(抽屉原理)的详解
  3. matlab---spectrogram短时傅里叶变换与chrip信号
  4. Eigen求解数学问题(一)
  5. java算法编程题_【java题目】考验你编程能力和算法的时候到了
  6. Gradle Introduction
  7. 使用canvas绘制时钟
  8. html 显示原始文本,Json显示为HTML文本 - 不是原始格式
  9. JavaSE的输入流、输出流
  10. 【笔试/面试】—— 从余弦定理到三角形两边之和大于第三边的证明
  11. 计算机需要那些高中数学知识点,高中必考数学知识点归纳整理
  12. 常用技术面试题(软件测试)
  13. QT应用编程: 获取系统当前时间以及1970到现在的总秒数
  14. 心形一行python_《心》字意思读音、组词解释及笔画数 - 新华字典 - 911查询
  15. 先正达谋定农化世界竞争格局-丰收节贸易会:座次重排
  16. 于飞SEO:零基础学seo难吗?怎么学?
  17. MySQL查询之分组查询
  18. Gamemaker studio2经验(2)——TCP联机
  19. 入门,前后端实现简单账号密码登录
  20. opengl全景图转换为天空盒图(成功)

热门文章

  1. mysql建立参照完整性,MySQL外键和参照完整性的实现步骤
  2. Surging实践经验
  3. python给出数据点进行插值_在Python中用“不动点”插值数据
  4. linux在vim中查找、退出
  5. mysql galera 脑裂_galera cluster集群的分裂与仲裁机制
  6. 玩QQ游戏,见到好几个图像是美女的QQ,就不始玩
  7. 【C++ 科学计算】C++ 计算总平方和、残差平方和
  8. sustech solidowrks
  9. C++获取系统图标方法
  10. C++11之nullptr