Python中篇 :2. asyncio和多线程结合实战

简介: Python中篇 :2. asyncio和多线程结合实战

1. 前言



看到这个题目大家觉得很慌,我都协程并发处理数据了,为什么还需要线程?孰轻孰重我们当然想的清楚,但是这里的门道就是一句话:我不管你异步编程多么NB,我就是想一边用异步,一边调用同步阻塞的代码,我不管我就这样用,你就说能不能办到?这可把我难倒了,上节课不是说了异步编程核心原则:要异步,所有的都要异步,感觉与其背道而驰啊。经过一番研究发现:草率了,异步中可以调用同步的代码,但是吃相比较难看而已罢了


2. 异步+同步



import time
import asyncio
from concurrent.futures.thread import ThreadPoolExecutor
# 同步阻塞代码
def run():
    time.sleep(2)
if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    start = time.time()
    executor = ThreadPoolExecutor() # 初始化线程池
    tasks = []
    for i in range(20):
        task = loop.run_in_executor(executor, run)
        tasks.append(task)
    loop.run_until_complete(asyncio.wait(tasks)) # 异步调用
    print("total time: ", time.time()-start)


执行时间:


total time:  4.015759229660034

20个同步阻塞任务在经过异步+同步调用之后时间增加了,但这是相比较于协程得出的结论(我们下面会分析)。我们可以看到程序通过ThreadPoolExecutor创建线程池,最后通过loop的run_in_executor把线程的future包装成协程的future,最后被loop的run_until_complete调度。


线程转换为协程 核心


为什么线程future可以转换成协程呢?

核心就是loop.run_in_executor方法,源码大家下去可以自己看,我只提取重点:return futures.wrap_future(executor.submit(func, *args), loop=self),看到了吗,线程执行的结果即executor.submit的返回值设置到concurrent.futures.Future对象里面(记为future1),而协程通过loop.create_future创建自己的future(记为future2),最后通过_chain_future将二者的future关联起来,即_chain_future(future1, future2),最后把future2返回,供loop调度。

分析到最后我忍不住感叹:吉多·范罗苏姆,你是一个天才选手。


3. all in 异步



import asyncio
import time
async def run1():
    await asyncio.sleep(2)
if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    start = time.time()
    tasks = []
    for i in range(20):
        tasks.append(run1())
    loop.run_until_complete(asyncio.wait(tasks))
    print("total time: ", time.time()-start)


运行结果如下:


total time:  2.0061399936676025

看到了吗?同样的代码逻辑,只要你把同步改成异步,那么效率会大大提升,即使有20个任务,每个任务sleep 2s,协程照样照单全收,几乎就是2s把所有任务执行完成,这效率无敌啊。


4. 小结



相信大家看到这里还有一点疑惑,到底哪种情况全是异步,那种情况同步+异步呢?来吧,开始你的表演:新项目,全是异步; 旧项目,看注释,说别动就别动,你动,就是bug,不动,万无一失,该如何破?教你一招:大胆破局

相关文章
|
4天前
|
存储 数据采集 数据库
Python爬虫实战:股票分时数据抓取与存储
Python爬虫实战:股票分时数据抓取与存储
|
5天前
|
Python
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
34 20
|
18天前
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
97 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
28天前
|
运维 Shell 数据库
Python执行Shell命令并获取结果:深入解析与实战
通过以上内容,开发者可以在实际项目中灵活应用Python执行Shell命令,实现各种自动化任务,提高开发和运维效率。
56 20
|
1月前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
106 61
Python装饰器实战:打造高效性能计时工具
|
2月前
|
数据采集 存储 XML
python实战——使用代理IP批量获取手机类电商数据
本文介绍了如何使用代理IP批量获取华为荣耀Magic7 Pro手机在电商网站的商品数据,包括名称、价格、销量和用户评价等。通过Python实现自动化采集,并存储到本地文件中。使用青果网络的代理IP服务,可以提高数据采集的安全性和效率,确保数据的多样性和准确性。文中详细描述了准备工作、API鉴权、代理授权及获取接口的过程,并提供了代码示例,帮助读者快速上手。手机数据来源为京东(item.jd.com),代理IP资源来自青果网络(qg.net)。
|
3月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
4月前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
5月前
|
数据采集 Linux 调度
Python之多线程与多进程
Python之多线程与多进程
42 0
|
6月前
|
数据采集 并行计算 程序员
Python中的并发编程:理解多线程与多进程
在Python编程中,理解并发编程是提升程序性能和效率的关键。本文将深入探讨Python中的多线程和多进程编程模型,比较它们的优劣势,并提供实际应用中的最佳实践与案例分析。

推荐镜像

更多