python异步编程
python用asyncio
模块实现异步编程,该模块最大特点就是,只存在一个线程
由于只有一个线程,就不可能多个任务同时运行。asyncio 是"多任务合作"模式(cooperative multitasking),允许异步任务交出执行权给其他任务,等到其他任务完成,再收回执行权继续往下执行
asyncio 模块在单线程上启动一个事件循环(event loop),时刻监听新进入循环的事件,加以处理,并不断重复这个过程,直到异步任务结束。
什么是事件循环?
单线程就意味着所有的任务需要在单线程上排队执行,也就是前一个任务没有执行完成,后一个任务就没有办法执行。在CPU密集型的任务之中,这样其实还行,但是如果我们的任务都是IO密集型的呢?也就是我们大部分的任务都是在等待网络的数据返回,等待磁盘文件的数据,这就会造成CPU一直在等待这些任务的完成再去执行下一个任务。
有没有什么办法能够让单线程的任务执行不这么笨呢?其实我们可以将这些需要等待IO设备的任务挂在一边嘛!这时候,如果我们的任务都是需要等待的任务,那么单线程在执行时遇到一个就把它挂起来,这里可以通过一个数据结构(例如队列)将这些处于执行等待状态的任务放进去,为什么是执行等待状态呢?因为它们正在执行但是又不得不等待例如网络数据的返回等等。直到将所有的任务都放进去之后,单线程就可以开始它的接连不断的表演了:有没有任务完成的小伙伴呀!快来我这里执行!
此时如果有某个任务完成了,它会得到结果,于是发出一个信号:我完成了。那边还在循环追问的单线程终于得到了答复,就会去看看这个任务有没有绑定什么回调函数呀?如果绑定了回调函数就进去把回调函数给执行了,如果没有,就将它所在的任务恢复执行,并将结果返回。
import asyncio import time async def get_html(url, name): print("%s get %s html start" % (name, url)) await asyncio.sleep(2) print("%s get %s html end" % (name, url)) if __name__ == '__main__': start=time.time() loop = asyncio.get_event_loop() # 创建两个协程 tasks = [ get_html("http://www.baidu.com", "A"), get_html("http://www.souhu.com", "B"), ] # 启动事件循环并将协程放进去执行 loop.run_until_complete(asyncio.wait(tasks)) end=time.time() print(end-start)
运行结果:
B get http://www.souhu.com html start A get http://www.baidu.com html start B get http://www.souhu.com html end A get http://www.baidu.com html end 2.0019772052764893