使用concurrent.futures模块

该模块包含以下几个类

concurrent.futures.Executor # 这是一个抽象类,提供异步执行的调用方法。
submit(function,argument)   # 安排某个函数执行。这里的函数是可调用对象,并给定参数。
map(function,argument)      # 以异步模式使用给定参数来执行函数
shutdown(Wait=True)         # 向执行器Executor传递释放资源的信号
concurrent.futures.Future   # 封装一个可调用函数的异步执行。通过向执行器提交任务来实例化Future对象

进程池和线程池

concurrent.futures.Executor下的两个子类

concurrent.futures.ThreadPoolExecutor(max_workers)
concurrent.futures.ProcessPoolExecutor(max_workers)

max_workers 表示异步调用的最大worker数量

具体实现

import concurrent.futures
import time

number_list = [1,2,3,4,5,6,7,8,9,10]


def count(number):
    i = None
    for i in range(0,10000000):
        i += 1
    return i*number

def evaluate_item(x):
    result_item = count(x)  # 随便写,只是为了增加一些操作
    print("item " + str(x) + " result: " + str(result_item))

if __name__ == '__main__':
    # *------------------------线性执行-----------------------------
    start_time = time.perf_counter()
    # perf_counter 和 process_time,time.clock()python3.8将废除
    for item in number_list:
        evaluate_item(item)
    print("线性执行 task: " + str(time.perf_counter()-start_time) +" s")

    # *------------------------线程池执行-----------------------------
    start_time_thread = time.perf_counter()
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        for item in number_list:
            executor.submit(evaluate_item,item)
        print("线程池 先打印,和with有关")
    print("线程池 task: " + str(time.perf_counter()-start_time_thread) +" s")

        # *------------------------进程池执行-----------------------------
    start_time_thread = time.perf_counter()
    with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
        for item in number_list:
            executor.submit(evaluate_item,item)
        print("进程池 先打印,和with有关")
    print("进程池 task: " + str(time.perf_counter()-start_time_thread) +" s")


"""
计算密集型: 进程
IO密集型  : 线程,协程(异步)
"""

使用Asyncio实现 时间循环管理

python模块的Asyncio提供了管理时间,协程,任务和线程的功能。

  • 时间循环(event loop):Asyncio模块 支持每个进程 拥有一个 事件循环。
  • 协程(coroutines):协程可以暂停,等待外部IO处理完成,再继续执行。
  • Futures:定义了Future对象,类似代表了尚未完成计算的concurrent.futures模块.
  • 任务(tasks):这是Asyncio的子类,用于封装并管理并行模式下的协程。

准备工作,Asyncio提供了用于管理 时间循环的方法

loop = get_event_loop() # 获取当前上下文的时间循环。
loop.call_later(time_delay,callback,argument) # 给定的时间后,调用某个回调对象
loop.call_soon(callback,argument) # 立刻调用某个回调对象。call_soon()返回 控制回到时间循环后 会立即调用
loop.time() #以浮点值的形式返回根据事件循环的内部时钟确定的当前时间
asyncio.set_event_loop() 将当前上下文的事件循环设置为给定循环。
asyncio.new_event_loop() 根据此函数的规则创建并返回一个新的事件循环对象
loop.run_forever() 一直执行,直到调用stop()为止。
import asyncio
import datetime
import time

def func_1(end_time,loop):
    print("func_1 called")
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1,func_2,end_time,loop)
    else:
        loop.stop()

def func_2(end_time,loop):
    print("func_2 called")
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1,func_3,end_time,loop)
    else:
        loop.stop()

def func_3(end_time,loop):
    print("func_3 called")
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1,func_1,end_time,loop)
    else:
        loop.stop()


def func_4(end_time,loop):
    print("func_4 called")
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1,func_4,end_time,loop)
    else:
        loop.stop()

loop = asyncio.get_event_loop()
end_loop = loop.time() + 9.0   # 9->8 看效果
loop.call_soon(func_1,end_loop,loop)
loop.call_soon(func_4,end_loop,loop)
loop.run_forever()
loop.close()

使用Asyncio 处理协程

有限状态机代码
"""
简化栗子
"""
import asyncio

@asyncio.coroutine
def start():
    print("start")
    yield from end("hello world")
    print("我 start 又回来了")


@asyncio.coroutine
def end(msg):
    print("end")
    print(msg)
    print("end over")

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(start())

使用asyncio管理任务

"""
通过asyncio.Task 并发三个数学函数
"""

import asyncio

@asyncio.coroutine
def factorial(number): # 阶乘
    f = 1
    for i in range(2,number+1):
        print(f"Asyncio.Task:Compute factorial({i})")
        yield from asyncio.sleep(1)
        f *= i
    print(f"Asyncio.Task - factorial({number})={f}")

@asyncio.coroutine
def fibonacci(number):# 斐波纳契
    a,b = 0,1
    for i in range(number):
        print(f"Asyncio.Task:Compute fibonacci({i})")
        yield from asyncio.sleep(1)
        a,b = b,a+b
    print(f"Asyncio.Task - fibonacci({number}) = {a}")


@asyncio.coroutine
def binomialCoeff(n,k): # 二项式
    result = 1
    for i in range(1,k+1):
        result = result * (n-i+1) / i
        print(f"Asyncio.Task:Compute binomialCoeff({i})")
        yield from asyncio.sleep(1)
    print(f"Asyncio.Task - binomialCoeff({n},{k}) = {result}")


if __name__ == '__main__':
    tasks = [
        asyncio.Task(factorial(10)),
        asyncio.Task(fibonacci(10)),
        asyncio.Task(binomialCoeff(20,10))
    ]

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

Asyncio 和 Futures

Asyncio模块的另外一个关键组件

它与concurrent.futures.Futures非常相似,但是已经按照asyncio的事件循环的主机制进行了调整。

asyncio.Future 类代表了一个还不可用的结果。因此,它是对尚需完成的任务的抽象表示。

事实上,哪些必须处理结果的回调对象也被算作该类的实例。

准备工作

import asyncio
future = asyncio.Futures()
  • cancel() 取消future 并安排回调对象
  • result() 返回future所代表的结果
  • exception() 返回future上设置的异常
  • add_done_callback(fn) 添加一个在future执行时运行的回调对象
  • remove_done_callback(fn) 从 “结束后调用(call when done)” 列表中移除一个回调对象的所有实例
  • set_result(result) 将future标记为已完成,并设置其结果
  • set_exception(exception) 将future标记为已完成,并设置一个异常
"""
Asyncio.Futures
"""

import asyncio
import sys

# 求n个整数的和
@asyncio.coroutine
def first_coroutine(future,N):
    count = 0
    for i in range(1,N+1):
        count = count + i
    yield from asyncio.sleep(3)
    future.set_result(f"求和 result is {count}")

# 求n的阶乘
@asyncio.coroutine
def second_coroutine(future,N):
    count = 1
    for i in range(2,N+1):
        count *= i
    yield from asyncio.sleep(4)
    future.set_result(f"阶乘 result is {count}")

def get_result(future):
    print(future.result())

if __name__ == '__main__':
    N1 = N2 = 2
    loop = asyncio.get_event_loop()

    future1 = asyncio.Future()
    future2 = asyncio.Future()

    tasks = [
        first_coroutine(future1,N1),
        second_coroutine(future2,N2)
    ]

    future1.add_done_callback(get_result)
    future2.add_done_callback(get_result)

    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

"""
改变N1 N2值
对调休眠时间
谁先执行完毕,谁先获取。
"""

async def和@asyncio.coroutine

asyncawait是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:

  1. @asyncio.coroutine替换为async
  2. yield from替换为await