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
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()
没有过不去的坎,只有没加够的油!