tornado学习笔记day07-同步与异步
同步
概念
同步就是按部就班的依次執行我們的代碼
進階
但是有些情況我們有一些比較耗時的從操作,比如去別的地方拿點資源,去其他網站請求數據,去訪問數據庫,上傳文件等等,所以這里面優點瑕疵,有小編一一道來
比如這樣
結果
開始處理reqA 開始耗時操作# 這里等待了5秒鐘 結束耗時操作 結束處理reqA 開始處理reqB 結束處理reqB在請求中添加了一個耗時的操作,導致了我們的同步的效率特別低了,這樣也體現不出我們tornado高效的優點
'''┌─┐ ┌─┐ + +┌──┘ ┴───────┘ ┴──┐++│ ││ ─── │++ + + +███████───███████ │+│ │+│ ─┴─ ││ │└───┐ ┌───┘│ ││ │ + +│ ││ └──────────────┐│ ││ ├─┐│ ┌─┘│ │└─┐ ┐ ┌───────┬──┐ ┌──┘ + + + +│ ─┤ ─┤ │ ─┤ ─┤└──┴──┘ └──┴──┘ + + + +神獸保佑代碼無BUG!'''異步
你干一件事情的同事又去干另一件事情
概述
對于耗時的操作,會交給別人(另一個線程)處理,我們繼續向下執行,當別人結束耗時操作后,再將處理結果返回給我們
回調函數實現異步
異步其實我們已經用了,js里面有一個很明顯的異步,就是在我們發ajax的時候,當我們發完ajax就去干別的活去了,后來ajax有響應了我們才搭理他
來來來,代碼演示如下:
''' #!/usr/bin/env python # -*- coding:utf-8 -*- # Created by victor ''' # 本模塊的功能:<異步演示demo># 這個就相等于一個客戶端的請求 import time import threading ''' 添加一個耗時的操作'''''' 這樣就會有一個問題,這個run()函數的返回值我們接受不到 為了解決這個問題,我們需要寫一個函數,這個函數叫做回調函數 ''' def longIO(callback):def run(cb):print("開始耗時操作")time.sleep(3)print("結束耗時操作")cb("victor is a wonderful man")threading.Thread(target=run,args=(callback,)).start()這個longio這部分 ,就像ajax一樣都不用我們來寫了
def finish(data):print("開始處理回調函數")print("接受到longIO的數據為:",data)print("結束處理回調函數")def reqA():print("開始處理reqA")longIO(finish)print("結束處理reqA")# 這個就相等于另一個客戶端的請求 def reqB():print("開始處理reqB")time.sleep(1)print("結束處理reqB") def main():# 這就是同步在處理reqA()reqB()while True:'''# 如果你要想寫死循環,你不要直接寫死循環,你得睡一睡# 為什么要睡一睡呢,因為你要是不睡你會發現你的CPU利用率占100%'''time.sleep(0.1)if __name__ == '__main__':main()異步只是說tornado能處理多個請求了,你瀏覽器該等還是得等著
協程實現異步
協程還不理解呢,還想實現異步,你就實現就行了
不用管擁護啥了,進程線程你們搞起來都麻煩呢,更別說協程了
版本1
最low的一個初級版本
''' #!/usr/bin/env python # -*- coding:utf-8 -*- # Created by victor ''' # 本模塊的功能:<># 這個就相等于一個客戶端的請求 import time import threadinggen = None# 添加一個耗時的操作 def longIO():def run():print("開始耗時操作")time.sleep(3)try:global gengen.send("victor is wonderful!!!")except StopIteration as e:passprint("結束耗時操作")threading.Thread(target=run,).start() # 這個longio這部分 ,就像ajax一樣都不用我們來寫了 ''' 這樣就會有一個問題,這個run()函數的返回值我們接受不到 為了解決這個問題,我們需要寫一個函數,這個函數叫做回調函數 '''def reqA():print("開始處理reqA")res = yield longIO()print("接受到longIO的數據為:",res)# 這里就相當于掛起了print("結束處理reqA")# 這個就相等于另一個客戶端的請求 def reqB():print("開始處理reqB")time.sleep(1)print("結束處理reqB")def main():# 這就是同步在處理global gengen = reqA() # 生成一個生成器next(gen) # 執行reqAreqB()while True:'''# 如果你要想寫死循環,你不要直接寫死循環,你得睡一睡# 為什么要睡一睡呢,因為你要是不睡你會發現你的CPU利用率占100%'''time.sleep(0.1)if __name__ == '__main__':main()版本2
我們有一個問題
版本1中在調用reqA的時候和reqB的調用方式可不一樣的啊
也就數不能將其視為簡單的函數,而是需要作為生成器來用,我們想的時候是當成一個普通函數來對待
現實
global gen gen = reqA() # 生成一個生成器 next(gen) # 執行reqA理想
reqA() # 僅僅的簡單的調用這個時候寄需要我們的裝飾器來登場了
''' 裝飾器還會寫么''' def genCoroutine(func):# 這個是帶有參數的裝飾器def wapper(*args,**kwargs):# 其實說白了還是那三句話global gengen = func(*args,**kwargs) # 生成一個生成器next(gen) # 執行reqAreturn wapper然后定義的時候
@genCoroutine def reqA():print("開始處理reqA")res = yield longIO()print("接受到longIO的數據為:",res)# 這里就相當于掛起了print("結束處理reqA")然后執行的時候
'''這個就相等于另一個客戶端的請求 ''' def reqB():print("開始處理reqB")time.sleep(1)print("結束處理reqB")def main():# 這就是同步在處理# global gen# gen = reqA() # 生成一個生成器# next(gen) # 執行reqAreqA()reqB()while True:'''# 如果你要想寫死循環,你不要直接寫死循環,你得睡一睡# 為什么要睡一睡呢,因為你要是不睡你會發現你的CPU利用率占100%'''time.sleep(0.1)if __name__ == '__main__':main()版本3
其實版本2中還有一個問題,他存在一個全局的gen變量,說白了就是假裝讓他不再那塊兒
這個是最復雜版本,看看吧
以后我們不用謝這么復雜的裝飾器了,tornado已經幫我們寫好了,你只要有異步就用裝飾器來裝飾一下就OK,其他的都不需要寫
tornado里面指正不是這么寫代碼,不然要是這樣寫,你們全費了,tornado留下的都是簡單易用的
這玩意不是你理解不理解,你一開始指定是不理解,你多用才能懂里面的原理
這個協程中的異步,其實他本質上不是協程,以為他用了多個線程,因為協程的定義是在一個線程里面玩的,只是來理解tornado實現原理
相似文章
tornado學習筆記day01 tornado學習筆記day02 tornado學習筆記day03 tornado學習筆記day04 tornado學習筆記day05 tornado學習筆記day06 tornado學習筆記day07 tornado學習筆記day08總結
以上是生活随笔為你收集整理的tornado学习笔记day07-同步与异步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【学习笔记】Task3 食物声音识别-音
- 下一篇: Day704.Tomcat内存溢出的原因