学Tornado的异步之前学了下Python的同步和异步机制,下面是三种实现Python中同步的方法。主要是用yield和装饰器以及threading模块实现。
python中异步的理解
同步
按部就班的依次执行
如果在请求中添加一个耗时操作,则必须等耗时操作结束才继续下去
一般不会用同步
异步
概述
对于耗时的操作,一般会交给另一个线程处理,我们继续向下执行,当别人结束耗时操作后再将结果返回给我们
回调函数实现异步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import time import threading
def longIo(callback): def run(cb): print("开始耗时操作") time.sleep(5) print("结束耗时操作") cb(" 我是返回的数据") threading.Thread(target=run,args=(callback,)).start()
def finish(data): print("开始处理回调函数") print("接收到longIo的相应数据:",data) print("结束处理回调函数")
def reqA(): print("开始处理reqA") longIo(finish) print("结束处理reqA")
def reqB(): print("开始处理reqB") longIo(finish) print("结束处理reqB")
def main(): reqA() reqB() while 1: time.sleep(0.1) pass
if __name__=='__main__': main()
|
协程实现异步
版本1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import time
gen = None
def longIo(callback): def run(cb): print("开始耗时操作") time.sleep(5) try: 引进全局变量并且用生成器回发数据 global gen gen.send("我是返回的数据") except StopIteration as e: pass print("结束耗时操作") threading.Thread(target=run).start()
def reqA(): print("开始处理reqA") res = yield longIo() print("接收longIo的相应数据:",res) print("结束处理reqA")
def reqB(): print("开始处理reqB") time.sleep(2) print("结束处理reqB")
def main(): global gen gen = reqA() next(gen)
reqB() while 1: time.sleep(0.1) pass
if __name__=='__main__': main()
|
版本2
问题
版本1中调用reqA的时候不能将其视为一个简单的函数,而是要作为生成器来对待
很明显要在主函数中要用三行调用reqA,只要用一行调用reqB。
解决办法
给reqA添加一个装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import time
gen
def longIo(callback): def run(cb): print("开始耗时操作") time.sleep(5) try: 引进全局变量并且用生成器回发数据 global gen gen.send("我是返回的数据") except StopIteration as e: pass print("结束耗时操作") threading.Thread(target=run).start()
def genCoroutine(func): def wrapper(*args, **kwargs): global gen gen = func(*args, **kwargs) next(gen) return wrapper
@genCoroutine def reqA(): print("开始处理reqA") res = yield longIo() print("接收longIo的相应数据:",res) print("结束处理reqA")
def reqB(): print("开始处理reqB") time.sleep(2) print("结束处理reqB")
def main(): reqA() reqB() while 1: time.sleep(0.1) pass
if __name__=='__main__': main()
|
版本3
问题
版本2中存在一个全局变量gen,需要消除
解决办法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import time
def genCoroutine(func): def wrapper(*args, **kwargs): gen1 = func() gen2 = next(gen1) def run(g): res = next(g) try: gen1.send(res) except StopIteration as e: pass threading.Thread(target=run,args=(gen2,)).start()
return wrapper
def longIo(callback): print("开始耗时操作") time.sleep(5) print("结束耗时操作") yield "我是返回的数据"
@genCoroutine def reqA(): print("开始处理reqA") res = yield longIo() print("接收longIo的相应数据:",res) print("结束处理reqA")
def reqB(): print("开始处理reqB") time.sleep(2) print("结束处理reqB")
def main(): reqA() reqB() while 1: time.sleep(0.1) pass
if __name__=='__main__': main()
|