问题

根据官方描述,asyncio中的事件是属于单个线程的,下面这段程序中即属于main线程。但是为什么下面的ThreadPollExecutor(2)中的两个线程的能共享一个loop?

拜托大神解释一下事件循环的本质到底是什么?官方文档只提供了一系列的api,到现在我也并没有真正的理解。

import asyncio
from concurrent.futures import ThreadPoolExecutorprint('running async test')def say_boo():i = 0while i < 10:print('...boo {0}'.format(i))i += 1def say_baa():i = 0while i < 10:print('...baa {0}'.format(i))i += 1if __name__ == "__main__":executor = ThreadPoolExecutor(2)loop = asyncio.get_event_loop()boo = asyncio.ensure_future(loop.run_in_executor(executor, say_boo))baa = asyncio.ensure_future(loop.run_in_executor(executor, say_baa))

回答

首先,event loop 就是一个普通 Python 对象,您可以通过 asyncio.new_event_loop() 创建无数个 event loop 对象。只不过,loop.run_xxx() 家族的函数都是阻塞的,比如 run_until_complete() 会等到给定的 coroutine 完成再结束,而 run_forever() 则会永远阻塞当前线程,直到有人停止了该 event loop 为止。所以在同一个线程里,两个 event loop 无法同时 run,但这不能阻止您用两个线程分别跑两个 event loop。

其次再说 ThreadPoolExecutor。您也可以看到,它根本不是 asyncio 库的东西。当您创建一个 ThreadPoolExecutor 对象时,您实际上是创建了一个线程池。仅此而已,与 asyncio、event loop 并无瓜葛。而当您明确使用一个 event loop 的 run_in_executor() 方法时,其实底层做的只有两件事:

  1. 用线程池执行给定函数,与 asyncio 毫无关系;
  2. 给线程池执行结果增加一个回调,该回调会在 event loop 的下一次循环中保存执行结果。

所以 run_in_executor() 只是将传统的线程池结果拉回到给定 event loop 中,以便进一步处理而已,不存在谁共享谁的关系,指定谁是谁。您可以尝试一下,在多个线程中跑多个 event loop,然后都向同一个线程池扔任务,然后返回结果:

import asyncio
import threading
import time
from concurrent.futures import ThreadPoolExecutore = ThreadPoolExecutor()def worker(index):print(index, 'before:', time.time())time.sleep(1)print(index, 'after:', time.time())return indexdef main(index):loop = asyncio.new_event_loop()rv = loop.run_until_complete(loop.run_in_executor(e, worker, index))print('Thread', index, 'got result', rv)threads = []
for i in range(5):t = threading.Thread(target=main, args=(i,))t.start()threads.append(t)for t in threads:t.join()

结果大致如下:

0 before: 1525751873.5256991
1 before: 1525751873.526891
3 before: 1525751873.527435
4 before: 1525751873.5278442
2 before: 1525751873.5282440 after: 1525751874.526666
1 after: 1525751874.5270479
Thread 1 got result 1
Thread 0 got result 0
3 after: 1525751874.532167
2 after: 1525751874.532394
4 after: 1525751874.5327559
Thread 4 got result 4
Thread 3 got result 3
Thread 2 got result 2

那为什么会有一个进程/线程一个 event loop 的说法呢?这是来源于默认 event loop 的概念,也就是 asyncio.get_event_loop()。初始情况下,get_event_loop() 只会在主线程帮您创建新的 event loop,并且在主线程中多次调用始终返回该 event loop;而在其他线程中调用 get_event_loop() 则会报错,除非您在这些线程里面手动调用过 set_event_loop()。细节请参考 文档。

最后关于您的问题“事件循环的本质到底是什么”:event loop 本身是一个循环,您可以看 asyncio.base_events.BaseEventLoop._run_once() 的源码,每个循环就执行这些东西。抛开所有的繁杂,每次循环只做两件事:

  1. 干等,什么也不做,一直等到有事件发生;
  2. 调用之前注册在这个事件上的处理代码。

仅此而已。这里的事件主要包括定时器事件和 I/O 事件,所有跑在 event loop 上的您的代码都是由一个事件触发的,然后反复地交错地跑,宏观上看就是异步并发了。

python3 asyncio loop 使用线程池原理相关推荐

  1. python3 线程池源码解析_5分钟看懂系列:Python 线程池原理及实现

    概述 传统多线程方案会使用"即时创建, 即时销毁"的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器 ...

  2. Java多线程系列--【JUC线程池 02】- 线程池原理(一)

    参考:http://www.cnblogs.com/skywang12345/p/java_threads_category.html 概要 在前面一章"Java多线程系列--"J ...

  3. 并发编程之 Executor 线程池原理与源码解读

    并发编程之 Executor 线程池原理与源码解读 线程是调度 CPU 资源的最小单位,线程模型分为 KLT 模型与 ULT 模型,JVM使用的是 KLT 模型.java线程与 OS 线程保持 1:1 ...

  4. 并发编程之Executor线程池原理与源码解读

    1. 线程池 "线程池",顾名思义就是一个线程缓存,线程是稀缺资源,如果被无限制的创建,不 仅会消耗系统资源,还会降低系统的稳定性,因此Java中提供线程池对线程进行统一分配. 调 ...

  5. Java多线程闲聊(四):阻塞队列与线程池原理

    Java多线程闲聊(四)-阻塞队列与线程池原理 前言 复用永远是人们永恒的主题,这能让我们更好地避免重复制造轮子. 说到多线程,果然还是绕不开线程池,那就来聊聊吧. 人们往往相信,世界是存在一些规律的 ...

  6. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础--线程安全性 Java 并发编程--Callable+Future+FutureTask java 并发编程--Thread 源码重新学习 java并发 ...

  7. JAVA线程池原理以及几种线程池类型介绍

    在什么情况下使用线程池? 1.单个任务处理的时间比较短      2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销      2.如不使用线程池, ...

  8. java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...

    线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...

  9. C++线程池原理及创建(转)

    C++线程池原理及创建(转) 来自http://www.cnblogs.com/cpper-kaixuan/p/3640485.html 本文给出了一个通用的线程池框架,该框架将与线程执行相关的任务进 ...

最新文章

  1. 在Ubuntu 18.04上实际安装OpenJDK 11
  2. [笔记]前端 - 下拉菜单的实现
  3. 调试maven源代码
  4. 集合的常用方法(增加、删除、并集、交集、差集、对等差分、超集和子集)
  5. Head First 设计模式--1策略模式 组合优于继承
  6. Jquery 实现动态加入table tr 和删除tr 以及checkbox的全选 和 获取加入TR删除TR后的数据...
  7. 牛!发出中国第一封电子邮件,注册登记域名 CN,中国互联网之父传奇
  8. CCF认证历年试题集
  9. Linux下安装和卸载jdk及环境配置
  10. Java多线程总结之线程安全队列Queue
  11. .text urlRewrite介绍
  12. 基于栈的字节码解释执行引擎图解
  13. CSDN日报20170602 ——《程序员、技术主管和架构师》
  14. 使用Texmacs帮助您写格式规范统一的BLOG
  15. Zabbix安装配置详解
  16. Quitting an application - is that frowned upon?
  17. 基于Python+Django+MySQL的大学生信用评估系统
  18. LessLyrics 苹果Mac歌词软件 iTunes歌词助手
  19. S3C2440 I2C实现
  20. [学习笔记]模拟退火

热门文章

  1. 计算机网络基础 — 网络的类型
  2. Busybox下的microcom用法
  3. NR 5G 移动性和状态变化
  4. Hyperscan-5.1.0 安装
  5. mysql /tmp目录爆满问题的处理
  6. 进程同步控制 Lock Semaphore Event
  7. 京东玩三角恋,结果“擦枪走火”
  8. 《机器人与数字人:基于MATLAB的建模与控制》——2.2节李群和李代数
  9. jquery ajax(实现单独提交某个form)
  10. Python多版本共存之pyenv