一、同步與異步
并發(fā):同一個(gè)世界换棚,但CPU只執(zhí)行一個(gè)任務(wù)
并行:多CPU同時(shí)執(zhí)行不同任務(wù)
同步:對(duì)請(qǐng)求結(jié)果來說式镐,上一步的操作必須執(zhí)行完畢,下一步才能執(zhí)行
異步:下一步的操作不需要等待上一步的完成
阻塞和非阻塞針對(duì)線程的狀態(tài)而言的:
阻塞:線程沒有資源固蚤,因此掛起并不執(zhí)行
非阻塞:線程有資源娘汞,一直運(yùn)行
tornado是異步非阻塞框架
tornado的異步代碼
注意:以下代碼使用的tornado的版本是4.5的,高版本不兼容夕玩。
import tornado.web
import tornado.ioloop
import tornado.httpclient
class IndexHandler(tornado.web.RequestHandler):
def get(self):
# 在路由中傳遞的參數(shù)你弦,/index/?q=python
q = self.get_argument('q')
# 向地址發(fā)送請(qǐng)求:https://cn.bing.com/search?q=
client = tornado.httpclient.HTTPClient()
response = client.fetch('https://cn.bing.com/search?q=%s' % q)
print(response)
self.write('同步測試')
def make_app():
return tornado.web.Application(handlers=[
(r'/index/', IndexHandler),
])
if __name__ == '__main__':
app = make_app()
app.listen(80)
tornado.ioloop.IOLoop.current().start()
tornado 異步代碼
import tornado.web
import tornado.ioloop
import tornado.httpclient
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self):
q = self.get_argument('q')
client = tornado.httpclient.AsyncHTTPClient()
client.fetch('https://cn.bing.com/search?q=%s' % q, callback=self.on_response)
self.write('異步測試')
def on_response(self, response):
# 回調(diào),當(dāng)頁面響應(yīng)惊豺,則調(diào)用回調(diào)函數(shù)on_response
print(response)
self.write('回調(diào)執(zhí)行')
self.finish()
def make_app():
return tornado.web.Application(handlers=[
(r'/index/', IndexHandler),
])
if __name__ == '__main__':
app = make_app()
app.listen(8080)
tornado.ioloop.IOLoop.current().start()
tornado 異步代碼優(yōu)化
import tornado.web
import tornado.ioloop
import tornado.httpclient
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@tornado.web.gen.coroutine
def get(self):
q = self.get_argument('q')
client = tornado.httpclient.AsyncHTTPClient()
response = yield client.fetch('https://cn.bing.com/search?q=%s' % q)
print(response)
self.write('異步測試')
def make_app():
return tornado.web.Application(handlers=[
(r'/index/', IndexHandler),
])
if __name__ == '__main__':
app = make_app()
app.listen(8090)
tornado.ioloop.IOLoop.current().start()
二、測壓
工具:apache
網(wǎng)站性能壓力測試是服務(wù)器網(wǎng)站性能調(diào)優(yōu)過程中必不可缺少的一環(huán)禽作。只有讓服務(wù)器處在高壓情況下尸昧,才能真正體現(xiàn)出軟件、硬件等各種設(shè)置不當(dāng)所暴露出的問題旷偿。
ab是apache自帶的壓力測試工具烹俗。
1、原理
ab是apachebench命令的縮寫狸捅。
ab的原理:ab命令會(huì)創(chuàng)建多個(gè)并發(fā)訪問線程衷蜓,模擬多個(gè)訪問者同時(shí)對(duì)某一URL地址進(jìn)行訪問。
ab工具的使用.jpg
2尘喝、名詞說明
名稱 | 英語 | 說明 |
---|---|---|
吞吐率 | Requests per second | 服務(wù)器并發(fā)處理能力的量化描述磁浇,單位是reqs/s |
并發(fā)連接數(shù) | The number of concurrent connections | 某個(gè)時(shí)刻服務(wù)器所接受的請(qǐng)求數(shù)目,簡單的講朽褪,就是一個(gè)會(huì)話 |
并發(fā)用戶數(shù) | The number of concurrent users置吓,Concurrency Level | 一個(gè)用戶可能同時(shí)會(huì)產(chǎn)生多個(gè)會(huì)話,也即連接數(shù) |
用戶平均請(qǐng)求等待時(shí)間 | Time per request | 處理完成所有請(qǐng)求數(shù)所花費(fèi)的時(shí)間/ (總請(qǐng)求數(shù) / 并發(fā)用戶數(shù)) |
服務(wù)器平均請(qǐng)求等待時(shí)間 | Time per request: across all concurrent requests | 處理完成所有請(qǐng)求數(shù)所花費(fèi)的時(shí)間 / 總請(qǐng)求數(shù) |
3缔赠、ab工具的使用
- 打開cmd
- 打開你安裝的apache的位置:找到 bin文件夾下面的ab.exe
- 輸入 ab.exe -help衍锚,查看命令幫助信息。
測試命令格式:ab [options] [http://]hostname[:port]/path
例如:測試本地代碼
ab -c 3 -n 10 http://127.0.0.1:80/index
ab測試結(jié)果.jpg
三嗤堰、聊天室
manage.py
import os
import tornado.web
import tornado.ioloop
from tornado.options import define, options, parse_command_line
from app.views import LoginHandler, ChatHandler
define('port', default=80, type=int)
def make_app():
return tornado.web.Application(handlers=[
(r'/login/', LoginHandler),
(r'/chat/', ChatHandler)
],
template_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates'),
static_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static'),
cookie_secret = 'w3rwefsaf'
)
if __name__ == '__main__':
parse_command_line()
app=make_app()
app.listen(80)
tornado.ioloop.IOLoop.current().start()
app/views.py
from datetime import datetime
import tornado.web
import tornado.websocket
class LoginHandler(tornado.web.RequestHandler):
def get(self):
error = None
self.render('login.html', error=error)
def post(self):
username = self.get_argument('username')
password = self.get_argument('password')
# self.get_body_argument()
# 模擬登錄,校驗(yàn)功能
if username in ['ququ','coco'] and password == '123':
self.set_secure_cookie('username', username)
self.render('chat.html', username=username)
else:
error = '賬號(hào)或密碼錯(cuò)誤!'
self.render('login.html', error=error)
class ChatHandler(tornado.websocket.WebSocketHandler):
# 用于存放連接的對(duì)象
user_online = []
def open(self):
self.user_online.append(self)
for user in self.user_online:
# 當(dāng)進(jìn)入chat.html頁面是戴质,會(huì)主動(dòng)觸發(fā)改函數(shù)
username = self.get_secure_cookie('username').decode('utf-8')
user.write_message('系統(tǒng)提示:[%s 已上線!]'% username)
def on_message(self, message):
# 接收前端返回額數(shù)據(jù)
username = self.get_secure_cookie('username').decode('utf-8')
for user in self.user_online:
str_time = (datetime.now()).strftime("%H:%M")
user.write_message('[%s]<br>%s:%s'% (str_time, username, message))
def on_close(self):
# 移除連接對(duì)象
self.user_online.remove(self)
for user in self.user_online:
username =self.get_secure_cookie('username').decode('utf-8')
user.write_message('系統(tǒng)提示:[%s已下線踢匣!]'% username)
在chat.html中添加
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
// 建立連接
var websocket = new WebSocket('ws://127.0.0.1/chat/')
// 獲取后端返回的數(shù)據(jù)
websocket.onmessage = function(e){
console.log(e.data)
$('#chat').append('<br>')
$('#chat').append(e.data)
}
$('#btn').click(function(){
// 向后端發(fā)送數(shù)據(jù)
var content = $('#content').val()
websocket.send(content)
});
</script>