(這篇文章主要寫一下在tornado項目中寫異步代碼,但是對源碼理解不了,寫給自己看)
當(dāng)初做項目的時候,我選擇了facebook的開源框架tornado,首先在項目中有一些比較耗時或者遠(yuǎn)程調(diào)用的邏輯,另外是它的高性能,加上以前自己做個人的東西,算是熟悉,最好名字很酷
1.為什么要寫異步代碼,在項目中有這樣一個需求,需要調(diào)用第三方短信平臺發(fā)送用戶的短信注冊碼,對于這種遠(yuǎn)程調(diào)用api的業(yè)務(wù)寫異步代碼可能比同步要好了据沈。
tornado對異步代碼做了處理,使用裝飾器和異步客戶端就會改變傳統(tǒng)的callback回調(diào)方式,像寫同步代碼一樣寫異步代碼了孙援。裝飾器@gen.coroutine礁竞,在tornado3.0以前使用@gen.engine 弧轧。異步客戶端tornado.httpclient.AsyncHTTPClient(). ?先上代碼
class SMS_bechtech:
? ? @gen.coroutine ? ?#1.異步裝飾器
? ? def send_sms(self, pnumber, temp, temp_param ,msgTemplate=None) :
? ? ? ? content = '尊敬的%s用戶,%s是您本次的驗證碼室奏,感謝您的使用!【xxxxx】'%(
? ? ? ? str(temp_param['pnumber']), str(temp_param['vc']))
? ? ? ? try:
? ? ? ? ? ? h = tornado.httpclient.AsyncHTTPClient() ? ? #2.異步客戶端
? ? ? ? ? ? params = urllib.urlencode( {'accesskey': 'xxxxx
? ? ? ? ? ? ? ? ? ? , 'secretkey':'xxxxx'
? ? ? ? ? ? ? ? ? ? , 'mobile': str(pnumber)
? ? ? ? ? ? ? ? ? ? , 'content' : content})
? ? ? ? ? ? ?h_response = yield h.fetch('http://sms.bechtech.cn/Api/send/data/json?%s'%(params)) ? ? #3.遠(yuǎn)程調(diào)用
? ? ? ? ? ? ?result = int(json.loads(h_response.body).get("result"))
? ? ? ? ?except Exception as e:
? ? ? ? ? ? ? logging.exception('SMS_bechtech send sms.')
? ? ? ? ? ? ? raise ecode.SMS_REQ_API_ERROR
''
主要關(guān)注斜體的部分就好了,關(guān)鍵三步
@gen.coroutine? ? #1.異步裝飾器
看源碼coroutine函數(shù)調(diào)用_make_coroutine_wrapper(func, replace_callback)函數(shù)? 我想IOLoop.current().add_future(future, lambda future: callback(future.result())) 將回調(diào)函數(shù)注冊到了ioloop的_callback事件列表中去了,此時進(jìn)程不會處于掛起或者就緒狀態(tài)等待IO,依然可以處理其他請求椎麦。
還要調(diào)用Runner(result, future, yielded)? 在Runner構(gòu)造函數(shù)中調(diào)用了run()函數(shù),yielded = self.gen.send(value) ? 通過send把參數(shù)傳遞給yield表達(dá)式
需要注意的是使用異步裝飾器, 還要是用異步的客戶端, 保證這2點才能保證請求是異步的, 比如函數(shù)中tornado.httpclient.AsyncHTTPClient()是http的異步客戶端, 還有比如motor的mongodb客戶端, 還有mysql等等實現(xiàn)的異步客戶端