动态添加协程

在实战之前,我们要先了解下在asyncio中如何将协程态添加到事件循环中的。这是前提。

如何实现呢,有两种方法:

  • 主线程是同步
import time
import asyncio
from queue import Queue
from threading import Thread def start_loop(loop):
# 一个在后台永远运行的事件循环
asyncio.set_event_loop(loop)
loop.run_forever() def do_sleep(x, queue, msg=""):
time.sleep(x)
queue.put(msg) queue = Queue() new_loop = asyncio.new_event_loop() # 定义一个线程,并传入一个事件循环对象
t = Thread(target=start_loop, args=(new_loop,))
t.start() print(time.ctime()) # 动态添加两个协程
# 这种方法,在主线程是同步的
new_loop.call_soon_threadsafe(do_sleep, 6, queue, "第一个")
new_loop.call_soon_threadsafe(do_sleep, 3, queue, "第二个") while True:
msg = queue.get()
print("{} 协程运行完..".format(msg))
print(time.ctime())

由于是同步的,所以总共耗时6+3=9秒.

输出结果

Thu May 31 22:11:16 2018
第一个 协程运行完..
Thu May 31 22:11:22 2018
第二个 协程运行完..
Thu May 31 22:11:25 2018
  • 主线程是异步
import time
import asyncio
from queue import Queue
from threading import Thread def start_loop(loop):
# 一个在后台永远运行的事件循环
asyncio.set_event_loop(loop)
loop.run_forever() async def do_sleep(x, queue, msg=""):
await asyncio.sleep(x)
queue.put(msg) queue = Queue() new_loop = asyncio.new_event_loop() # 定义一个线程,并传入一个事件循环对象
t = Thread(target=start_loop, args=(new_loop,))
t.start() print(time.ctime()) # 动态添加两个协程
# 这种方法,在主线程是异步的
asyncio.run_coroutine_threadsafe(do_sleep(6, queue, "第一个"), new_loop)
asyncio.run_coroutine_threadsafe(do_sleep(3, queue, "第二个"), new_loop) while True:
msg = queue.get()
print("{} 协程运行完..".format(msg))
print(time.ctime())

输出结果 由于是同步的,所以总共耗时max(6, 3)=6秒 Thu May 31 22:23:35 2018
第二个 协程运行完..
Thu May 31 22:23:38 2018
第一个 协程运行完..
Thu May 31 22:23:41 2018

实战:利用redis实现动态添加任务

对于并发任务,通常是用生成消费模型,对队列的处理可以使用类似master-worker的方式,master主要用户获取队列的msg,worker用户处理消息。

为了简单起见,并且协程更适合单线程的方式,我们的主线程用来监听队列,子线程用于处理队列。这里使用redis的队列。主线程中有一个是无限循环,用户消费队列。

服务开启后,我们就可以运行我们的客户端了。
并依次输入key=queue,value=5,3,1的消息。

一切准备就绪之后,我们就可以运行我们的代码了。

import time
import redis
import asyncio
from queue import Queue
from threading import Thread def start_loop(loop):
# 一个在后台永远运行的事件循环
asyncio.set_event_loop(loop)
loop.run_forever() async def do_sleep(x, queue):
await asyncio.sleep(x)
queue.put("ok") def get_redis():
connection_pool = redis.ConnectionPool(host='127.0.0.1', db=0)
return redis.Redis(connection_pool=connection_pool) def consumer():
while True:
task = rcon.rpop("queue")
if not task:
time.sleep(1)
continue
asyncio.run_coroutine_threadsafe(do_sleep(int(task), queue), new_loop) if __name__ == '__main__':
print(time.ctime())
new_loop = asyncio.new_event_loop() # 定义一个线程,运行一个事件循环对象,用于实时接收新任务
loop_thread = Thread(target=start_loop, args=(new_loop,))
loop_thread.setDaemon(True)
loop_thread.start()
# 创建redis连接
rcon = get_redis() queue = Queue() # 子线程:用于消费队列消息,并实时往事件对象容器中添加新任务
consumer_thread = Thread(target=consumer)
consumer_thread.setDaemon(True)
consumer_thread.start() while True:
msg = queue.get()
print("协程运行完..")
print("当前时间:", time.ctime())

输出结果

Thu May 31 23:42:48 2018
协程运行完..
当前时间: Thu May 31 23:42:49 2018 协程运行完..
当前时间: Thu May 31 23:42:51 2018 协程运行完..
当前时间: Thu May 31 23:42:53 2018
  • loop_thread:单独的线程,运行着一个事件对象容器,用于实时接收新任务。
  • consumer_thread:单独的线程,实时接收来自Redis的消息队列,并实时往事件对象容器中添加新任务。

我们在Redis,分别发起了5s3s1s的任务。
从结果来看,这三个任务,确实是并发执行的,1s的任务最先结束,三个任务完成总耗时5s

运行后,程序是一直运行在后台的,我们每一次在Redis中输入新值,都会触发新任务的执行。

出处:https://www.cnblogs.com/wongbingming/p/9124142.html

IO框架:asyncio 下篇的更多相关文章

  1. 爬虫之多线程 多进程 自定义异步IO框架

    什么是进程? 进程是程序运行的实例,是系统进行资源分配和调度的一个独立单位,它包括独立的地址空间,资源以及1个或多个线程. 什么是线程? 线程可以看成是轻量级的进程,是CPU调度和分派的基本单位. 进 ...

  2. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  3. socket.io框架

    socket.io框架 一.问题背景 目前公司在互联网产品上需要程序与前端部分要进行一个实时交互,在进行一定程度上的选型后,决定使用socket.io框架进行一个实践,算是公司的一个新的 尝试,也算是 ...

  4. (转)Python黑魔法 --- 异步IO( asyncio) 协程

    转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...

  5. java IO框架分析

    jave.io框架 2010-11-10 22:18:34|  分类: 默认分类|举报|字号 订阅     可从IO的类层次,IO框架的设计模式来论述. 总体来说,IO可以分为字节流和字符流,不同在于 ...

  6. Python并发编程之实战异步IO框架:asyncio 下篇(十一)

    大家好,并发编程 进入第十一章. 前面两节,我们讲了协程中的单任务和多任务 这节我们将通过一个小实战,来对这些内容进行巩固. 在实战中,将会用到以下知识点: 多线程的基本使用 Queue消息队列的使用 ...

  7. Python并发编程之初识异步IO框架:asyncio 上篇(九)

    大家好,并发编程 进入第九篇. 通过前两节的铺垫(关于协程的使用),今天我们终于可以来介绍我们整个系列的重点 -- asyncio. asyncio是Python 3.4版本引入的标准库,直接内置了对 ...

  8. Python并发编程之学习异步IO框架:asyncio 中篇(十)

    大家好,并发编程 进入第十章.好了,今天的内容其实还挺多的,我准备了三天,到今天才整理完毕.希望大家看完,有所收获的,能给小明一个赞.这就是对小明最大的鼓励了.为了更好地衔接这一节,我们先来回顾一下上 ...

  9. 异步IO框架:asyncio 中篇

    上一节我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主 ...

随机推荐

  1. kubeadm快速安装k8s

    1.安装net-tools [root@localhost ~]# yum install -y net-tools 2.关闭firewalld [root@localhost ~]# systemc ...

  2. 请求头出现Provisional headers are shown

    provisional headers are shown 知多少:https://juejin.im/post/5c00980751882518805add83 请求头出现Provisional h ...

  3. RestTemplateBuilder类

    Spring Boot使用RestTemplate消费REST服务的几个问题记录 我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调 ...

  4. java实验题目

    1. 打印输出所有的“水仙花数”,所谓“水仙花数”是指一个3位数,其中各位数字立方和等于该数本身.例如,153是一个“水仙花数”. 实验源码: public class number1 { publi ...

  5. 19.通过MAPREDUCE 把收集数据进行清洗

    在eclipse软件里创建一个maven项目 jdk要换成本地安装的1.8版本的 加载pom.xml文件 <project xmlns="http://maven.apache.org ...

  6. 【转帖】安卓的Bionic 简介

    https://blog.csdn.net/yongyu_it/article/details/52574797 google 自己实现了一套libc 的库函数 比glibc 要小一些 占用内存也小. ...

  7. mysql之存储过程基础

    存储过程 procedure 可以理解为一个处理增删改,没有返回值得函数 创建存储过程的基本语法 create procedure 过程名 ([参数列表]) begin --过程体 end 存储过程主 ...

  8. Active Learning 主动学习

    Active Learning 主动学习 2015年09月30日 14:49:29 qrlhl 阅读数 21374 文章标签: 算法机器学习 更多 分类专栏: 机器学习   版权声明:本文为博主原创文 ...

  9. UI语言杂集

    最适合做 GUI 的是 DSL 或者 XML(以及 XML 的扩展)之类的标记语言,而不是编程语言. 例如 Qt 的 QML,Android 的 XML 或者 WPF 的 XAML 以及大家都再熟悉不 ...

  10. JSON函数表2

    [class] Json::Reader [public] [将字符串或者输入流转换为JSON的Value对象] bool parse( const std::string &document ...