asyncio

1,事件循环

import asyncio
import time # time.sleep()是同步阻塞的接口,在async中不可以使用
async def get_html(url):
    print("start get url")
    await asyncio.sleep(2)  # 在协程中不要加传统的等待时间,如果非要加的话,就必须在前面加一个await,表明需要等待它完成
    print("end get url")

if __name__ == "__main__":
    start_time = time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(get_html('www.baidu.com'))
    print(time.time()-start_time)


>>>
start get url
0.0848842123546
end get url

当如果需要多个并发呢?

#使用asyncio
import asyncio
import time # time.sleep()是同步阻塞的接口,在async中不可以使用
async def get_html(url):
    print("start get url")
    await asyncio.sleep(2)  # 在协程中不要加传统的等待时间,如果非要加的话,就必须在前面加一个await,表明需要等待它完成
    print("end get url")

if __name__ == "__main__":
    start_time = time.time()
    loop = asyncio.get_event_loop()
    tasks = [get_html("http://www.baidu.com") for i in range(10)]
    loop.run_until_complete(asyncio.wait(tasks))
    print(time.time()-start_time)

最终执行的时间也不过是2s

但是如果使用的是time.sleep,就不可以达成并发

一、获取协程的返回值

import asyncio
import time
from functools import partial
async def get_html(url):
    print("start get url")
    await asyncio.sleep(2)
    return "OK"

def callback(url, future):
    print(url)
    print("send email to zl")

if __name__ == "__main__":
    start_time = time.time()
    loop = asyncio.get_event_loop()
    # get_future = asyncio.ensure_future(get_html("http://www.imooc.com"))  # 和下面方法等效
    task = loop.create_task(get_html("http://www.imooc.com"))  #和上面方法等效,将协程注册到事件循环中
    task.add_done_callback(partial(callback, "http://www.imooc.com"))  # 为什么使用偏函数,因为add_done_callback只能接受函数名,因此使用偏函数
    loop.run_until_complete(task)
   print(get_feture.result())
print(task.result())

你可能注意到上面还有一个callback,那这个是干什么用的呢?

callback:比如在一个URL下载完成之后,给我发送一封邮件,或者是耗时比较长的时候发送邮件

要注意的是,callback这个函数必须要有参数feture,那如果,我还想继续传参呢?

就使用partial(偏函数),这个函数可以将callback进行包装,但是callback需要额外传参的时候必须在前面写!,偏函数的返回值是函数名

"""
Python 偏函数是通过 functools 模块被用户调用。
偏函数 partial 应用

函数在执行时,要带上所有必要的参数进行调用。但是,有时参数可以在函数被调用之前提前获知。这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。

偏函数是将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的参数,除非使用关键字参数。

通过语言描述可能无法理解偏函数是怎么使用的,那么就举一个常见的例子来说明。在这个例子里,我们实现了一个取余函数,对于整数 100,取得对于不同数 m 的 100%m 的余数。
"""
from functools import partial
 
def mod( n, m ):
  return n % m
 
mod_by_100 = partial( mod, 100 )
 
print mod( 100, 7 )  # 2
print mod_by_100( 7 )  # 2
View Code

wait和 gather

#wait 和 gather
import asyncio
import time
async def get_html(url):
    print("start get url")
    await asyncio.sleep(2)
    print("end get url")

if __name__ == "__main__":
    start_time = time.time()
    loop = asyncio.get_event_loop()
    tasks = [get_html("http://www.imooc.com") for i in range(10)]
    # loop.run_until_complete(asyncio.gather(*tasks))
    # print(time.time()-start_time)

    #gather和wait的区别(优先考虑gather)
    #gather更加high-level
    group1 = [get_html("http://projectsedu.com") for i in range(2)]
    group2 = [get_html("http://www.imooc.com") for i in range(2)]
    group1 = asyncio.gather(*group1)
    group2 = asyncio.gather(*group2)
    group2.cancel()  # 呈批的取消
    loop.run_until_complete(asyncio.gather(group1, group2))
    print(time.time() - start_time)

协程的暂停:

首先来看一下:

# 1. run_until_complete
import asyncio
loop = asyncio.get_event_loop()
loop.run_forever()  #不会停止
loop.run_until_complete()  # 运行完指定协程后停止
loop会被放到future中
取消future(task)

先看一个例子:

import asyncio
import time

async def get_html(sleep_times):
    print("waiting")
    await asyncio.sleep(sleep_times)
    print("done after {}s".format(sleep_times))


if __name__ == "__main__":
    task1 = get_html(2)
    task2 = get_html(3)
    task3 = get_html(3)

    tasks = [task1, task2, task3]

    loop = asyncio.get_event_loop()
  loop.run_until_complete(asyncio.wait(tasks))
waiting
waiting
waiting
done after 2s
done after 3s
done after 3s

这一个时间循环是没有问题的

我们现在需要做的是取消

import asyncio
import time

async def get_html(sleep_times):
    print("waiting")
    await asyncio.sleep(sleep_times)
    print("done after {}s".format(sleep_times))


if __name__ == "__main__":
    task1 = get_html(2)
    task2 = get_html(3)
    task3 = get_html(3)

    tasks = [task1, task2, task3]

    loop = asyncio.get_event_loop()

    try:
        loop.run_until_complete(asyncio.wait(tasks))
    except KeyboardInterrupt as e:
        all_tasks = asyncio.Task.all_tasks()  # 可以获取到所有的task
        for task in all_tasks:
            print("cancel task")
            print(task.cancel())
        loop.stop()
        loop.run_forever()  # 这个很关键,不调用会抛出异常的
    finally:
        loop.close()
原文地址:https://www.cnblogs.com/zhoulixiansen/p/11191162.html