这个文章理好了脉落。
http://python.jobbole.com/86069/
我练 习了一番,感受好了很多。。。
Python由于众所周知的GIL的原因,导致其线程无法发挥多核的并行计算能力(当然,后来有了multiprocessing,可以实现多进程并行),显得比较鸡肋。既然在GIL之下,同一时刻只能有一个线程在运行,那么对于CPU密集的程序来说,线程之间的切换开销就成了拖累,而以I/O为瓶颈的程序正是协程所擅长的:
多任务并发(非并行),每个任务在合适的时候挂起(发起I/O)和恢复(I/O结束)
弄清楚了asyncio.coroutine和yield from之后,在Python3.5中引入的async和await就不难理解了:可以将他们理解成asyncio.coroutine/yield from的完美替身。当然,从Python设计的角度来说,async/await让协程表面上独立于生成器而存在,将细节都隐藏于asyncio模块之下,语法更清晰明了。
#!/usr/bin/env python# -*- coding: utf-8 -*-import asyncioimport timeimport random'''def old_fib(n): res = [0] * n index = 0 a = 0 b = 1 while index < n: res[index] = b a, b = b, a + b index += 1 return resprint("-"*10 + "test old fib " + "-"*10)for fib_res in old_fib(20): print(fib_res)def fib(n): index = 0 a = 0 b = 1 while index < n: yield b a, b = b, a + b index += 1print("-"*10 + "test yield fib " + "-"*10)for fib_res in fib(20): print(fib_res)def stupid_fib(n): index = 0 a = 0 b = 1 while index < n: sleep_cnt = yield b print("let me think {0} secs".format(sleep_cnt)) time.sleep(sleep_cnt) a, b = b, a + b index += 1print("-"*10 + "test yield send " + "-"*10)N = 20sfib = stupid_fib(N)fib_res = next(sfib)while True: print(fib_res) try: fib_res = sfib.send(random.uniform(0, 0.5)) except StopIteration: breakdef copy_fib(n): print("I am copy from fib") yield from fib(n) print("copy end")print("-"*10 + "test yield from " + "-"*10)for fib_res in copy_fib(20): print(fib_res)def copy_stupid_fib(n): print("I am copy from stupid fib") yield from stupid_fib(n) print("Copy end")print("-"*10 + "test yield from and send" + "-"*10)N = 20csfib = copy_stupid_fib(N)fib_res = next(csfib)while True: print(fib_res) try: fib_res = csfib.send(random.uniform(0, 0.5)) except StopIteration: break@asyncio.coroutinedef smart_fib(n): index = 0 a = 0 b = 1 while index < n: sleep_secs = random.uniform(0, 0.2) yield from asyncio.sleep(sleep_secs) print("Smart one think {} secs to get {}".format(sleep_secs, b)) a, b = b, a + b index += 1@asyncio.coroutinedef stupid_fib(n): index = 0 a = 0 b = 1 while index < n: sleep_secs = random.uniform(0, 0.4) yield from asyncio.sleep(sleep_secs) print("Stupid one think {} secs to get {}".format(sleep_secs, b)) a, b = b, a + b index += 1loop = asyncio.get_event_loop()tasks = [ asyncio.async(smart_fib(10)), asyncio.async(stupid_fib(10)), ]loop.run_until_complete(async.wait(tasks))print("All fib finished.")loop.close() ''' async def smart_fib(n): index = 0 a = 0 b = 1 while index < n: sleep_secs = random.uniform(0, 0.2) await asyncio.sleep(sleep_secs) print("Smart one think {} secs to get {}".format(sleep_secs, b)) a, b = b, a + b index += 1async def stupid_fib(n): index = 0 a = 0 b = 1 while index < n: sleep_secs = random.uniform(0, 0.4) await asyncio.sleep(sleep_secs) print("Stupid one think {} secs to get {}".format(sleep_secs, b)) a, b = b, a + b index += 1loop = asyncio.get_event_loop()tasks = [ asyncio.async(smart_fib(10)), asyncio.async(stupid_fib(10)), ]loop.run_until_complete(asyncio.wait(tasks))print("All fib finished.")loop.close()
Python中的协程经历了很长的一段发展历程。其大概经历了如下三个阶段:
- 最初的生成器变形yield/send
- 引入@asyncio.coroutine和yield from
- 在最近的Python3.5版本中引入async/await关键字