Python异步编程之美

一. Python中线程thread实现以及调度

高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程,一般线程是由操作系统进行直接调度的,例如当出现IO时,操作系统会自行实现实现线程切换,直接上代码:

# _*_ coding: utf-8 _*_
# !/usr/bin/python
"""
Author:mym
Create Date: -15:05
User: EDZ
description:
"""
import time
import threading


def decoration(func):
    def wrap(*args, **kwargs):
        work = threading.Thread(target=func, args=args, kwargs=kwargs)
        work.start()
    return wrap


@decoration
def say():
    time.sleep(3)
    print("in say work function")


def sing():
    print("in sing work function")


if __name__ == '__main__':
    say()
    sing()

输出结果:
in sing work function
间隔3秒
in say work function

解释一下,这里为什么先执行的时say()函数,但是确先执行sing()并打印"in sing work function",这是因为主进程的线程中我们调用threading模块创建了一个线程去执行say函数,然后遇到IO操作,此时操作系统自己会进行线程调度并进行线程切换,执行主线程的任务,然后IO操作结束后去执行work线程

注意点:高级语言中线程的切换时操作系统自行调度的

二. Python异步编程
2.1 asyncio异步api

异步过程

import threading
import asyncio


async def work():
    print("current threading name is %s" % threading.currentThread().name)
    await asyncio.sleep(1)
    print("await end")


async def main():
    await asyncio.gather(work(), work(), work())


if __name__ == '__main__':
    asyncio.run(main())

在 async 函数main的里面,asyncio.gather() 方法将多个异步任务(三个 work())包装成一个新的异步任务,必须等到内部的多个异步任务都执行结束,这个新的异步任务才会结束,三个 work() 依次执行,打印完"current threading name is" ,就休眠1秒钟,把执行权交给下一个work(),所以先连续打印出三个 “current threading name is”。等到1秒钟休眠结束,执行权重新交回第一个 work(),开始执行 await 命令下一行的语句,所以会接着打印出三个"await end",脚本总的运行时间是1秒。

2.2 concurrent.futures模块

concurrent.futures模块实现了对threading(线程)和multiprocessing(进程)的更高级的抽象,对编写线程池/进程池提供了直接的支持。
Python3.2以后提供了concurrent标准模块,其中concurrent.futures模块提供了两个支持异步的方法的类,ThreadPoolExecutor, ProcessPoolExecutor,顾名思义两者分别被用来创建线程池和进程池的代码。我们可以将相应的tasks直接放入线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动帮我们调度

Future这个概念你可以把它理解为一个在未来完成的操作,这是异步编程的基础,传统编程模式下比如我们操作queue.get的时候,在等待返回结果之前会产生阻塞,cpu不能让出来做其他事情,而Future的引入帮助我们在等待的这段时间可以完成其他的操作。

Future Objects:Future类封装了可调用的异步执行.Future 实例通过 Executor.submit()方法创建。

**submit(fn, *args, kwargs):调度可调用的fn,作为fn(args kwargs)执行,并返回一个表示可调用的执行的Future对象。
ThreadPoolExecutor:ThreadPoolExecutor是一个Executor的子类,它使用线程池来异步执行调用。

concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix=’’):Executor子类,使用max_workers规格的线程池来执行异步调用

接下来模拟在Flask应用中使用异步耗时任务:
在这里插入图片描述
从应用的执行逻辑我们可以看到concurrent.future中ThreadPoolExecutor中通过线程池异步执行了耗时的业务逻辑代码,主函数的视图结果可以快速返回,这种处理耗时的业务逻辑可以通过在数据设置status状态码来标识异步任务的执行状态,开始执行耗时业务逻辑代码我们可以设置status=0,然后待submit函数成功在修改数据的status=1,表示耗时业务逻辑代码执行成功(耗时业务逻辑代码可以是一个文件导出下载,或者redis等数据异步操作)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值