国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中asyncio與aiohttp入門教程

2020-01-04 14:20:53
字體:
來源:轉載
供稿:網友

很多朋友對異步編程都處于“聽說很強大”的認知狀態。鮮有在生產項目中使用它。而使用它的同學,則大多數都停留在知道如何使用 Tornado、Twisted、Gevent 這類異步框架上,出現各種古怪的問題難以解決。而且使用了異步框架的部分同學,由于用法不對,感覺它并沒牛逼到哪里去,所以很多同學做 Web 后端服務時還是采用 Flask、Django等傳統的非異步框架。

從上兩屆 PyCon 技術大會看來,異步編程已經成了 Python 生態下一階段的主旋律。如新興的 Go、Rust、Elixir 等編程語言都將其支持異步和高并發作為主要“賣點”,技術變化趨勢如此。Python 生態為不落人后,從2013年起由 Python 之父 Guido 親自操刀主持了Tulip(asyncio)項目的開發。

異步io的好處在于避免的線程的開銷和切換,而且我們都知道python其實是沒有多線程的,只是通過底層線層鎖實現的多線程。另一個好處在于避免io操作(包含網絡傳輸)的堵塞時間。

asyncio可以實現單線程并發IO操作。如果僅用在客戶端,發揮的威力不大。如果把asyncio用在服務器端,例如Web服務器,由于HTTP連接就是IO操作,因此可以用單線程+coroutine實現多用戶的高并發支持。

asyncio實現了TCP、UDP、SSL等協議,aiohttp則是基于asyncio實現的HTTP框架。

  • 對于異步io你需要知道的重點,要注意的是,await語法只能出現在通過async修飾的函數中,否則會報SyntaxError錯誤。而且await后面的對象需要是一個Awaitable,或者實現了相關的協議。

注意:

  • 所有需要異步執行的函數,都需要asyncio中的輪訓器去輪訓執行,如果函數阻塞,輪訓器就會去執行下一個函數。所以所有需要異步執行的函數都需要加入到這個輪訓器中。

asyncio

asyncio的基本概念asyncio是在python3.4中被引進的異步IO庫。你也可以通過python3.3的pypi來安裝它。它相當的復雜,而且我不會介紹太多的細節。相反,我將會解釋你需要知道些什么,以利用它來寫異步的代碼。簡而言之,有兩件事情你需要知道:協同程序和事件循環。協同程序像是方法,但是它們可以在代碼中的特定點暫停和繼續。當在等待一個IO(比如一個HTTP請求),同時執行另一個請求的時候,可以用來暫停一個協同程序。

例如:

import requestsimport timeimport asyncio# 創建一個異步函數async def task_func():  await asyncio.sleep(1)  resp = requests.get('http://192.168.2.177:5002/')  print('2222222',time.time(),resp.text)async def main(loop):  loop=asyncio.get_event_loop()  # 獲取全局輪訓器  task = loop.create_task(task_func()) # 在全局輪訓器加入協成,只有加入全局輪訓器才能被監督執行  await asyncio.sleep(2)  # 等待兩秒為了不要立即執行event_loop.close(),項目中event_loop應該是永不停歇的  print('11111111111',time.time())event_loop = asyncio.get_event_loop()try:  event_loop.run_until_complete(main(event_loop))finally:  event_loop.close()  # 當輪訓器關閉以后,所有沒有執行完成的協成將全部關閉

aiohttp服務器

下面是aiohttp作為服務器端的一個簡單的demo。

#!/usr/bin/env python3import argparsefrom aiohttp import webimport asyncioimport base64import loggingimport uvloopimport time,datetimeimport jsonimport requestsasyncio.set_event_loop_policy(uvloop.EventLoopPolicy())routes = web.RouteTableDef()@routes.get('/')async def hello(request):  return web.Response(text="Hello, world")# 定義一個路由映射,接收網址參數,post方式@routes.post('/demo1/{name}')async def demo1(request):  # 異步監聽,只要一有握手就開始觸發,此時網址參數中的name就已經知道了,但是前端可能還沒有完全post完數據。  name = request.match_info.get('name', "Anonymous") # 獲取name  print(datetime.datetime.now())  # 觸發視圖函數的時間  data = await request.post()  # 等待post數據完成接收,只有接收完成才能進行后續操作.data['key']獲取參數  print(datetime.datetime.now())  # 接收post數據完成的時間  logging.info('safety dect request start %s' % datetime.datetime.now())  result = {'name':name,'key':data['key']}  logging.info('safety dect request finish %s, %s' % (datetime.datetime.now(),json.dumps(result)))  return web.json_response(result)# 定義一個路由映射,設計到io操作@routes.post('/demo2')async def demo2(request):  # 異步監聽,只要一有握手就開始觸發,此時網址參數中的name就已經知道了,但是前端可能還沒有完全post完數據。  data = await request.post()  # 等待post數據完成接收,只有接收完成才能進行后續操作.data['key']獲取參數  logging.info('safety dect request start %s' % datetime.datetime.now())  res = requests.post('http://www.baidu.com')  # 網路id,會自動切換到其他協成上  logging.info('safety dect request finish %s' % res.test)  return web.Response(text="welcome")if __name__ == '__main__':  logging.info('server start')  app = web.Application()  app.add_routes(routes)  web.run_app(app,host='0.0.0.0',port=8080)  logging.info('server close')

aiohttp客戶端

aiohttp的另一個主要作用是作為異步客戶端,用來解決高并發請求的情況。比如現在我要模擬一個高并發請求來測試我的服務器負載情況。所以需要在python里模擬高并發。高并發可以有多種方式,比如多線程,但是由于python本質上是沒有多線程的,通過底層線程鎖實現的多線程。在模型高并發時,具有線程切換和線程開銷的損耗。所以我們就可以使用多協成來實現高并發。

我們就可以使用aiohttp來模擬高并發客戶端。demo如下,用來模擬多個客戶端向指定服務器post圖片。

# 異步并發客戶端class Asyncio_Client(object):  def __init__(self):    self.loop=asyncio.get_event_loop()    self.tasks=[]  # 將異步函數介入任務列表。后續參數直接傳給異步函數  def set_task(self,task_fun,num,*args):    for i in range(num):      self.tasks.append(task_fun(*args))  # 運行,獲取返回結果  def run(self):    back=[]    try:      f = asyncio.wait(self.tasks)  # 創建future      self.loop.run_until_complete(f) # 等待future完成    finally:      pass# 服務器高并發壓力測試class Test_Load():  total_time=0 # 總耗時  total_payload=0 # 總負載  total_num=0 # 總并發數  all_time=[]  # 創建一個異步任務,本地測試,所以post和接收幾乎不損耗時間,可以等待完成,主要耗時為算法模塊  async def task_func1(self,session):    begin = time.time()    # print('開始發送:', begin)    file=open(self.image, 'rb')    fsize = os.path.getsize(self.image)    self.total_payload+=fsize/(1024*1024)    data = {"image_id": "2", 'image':file}    r = await session.post(self.url,data=data) #只post,不接收    result = await r.json()    self.total_num+=1    # print(result)    end = time.time()    # print('接收完成:', end,',index=',self.total_num)    self.all_time.append(end-begin)  # 負載測試  def test_safety(self):    print('test begin')    async_client = Asyncio_Client() # 創建客戶端    session = aiohttp.ClientSession()    for i in range(10): # 執行10次      self.all_time=[]      self.total_num=0      self.total_payload=0      self.image = 'xxxx.jpg' # 設置測試nayizhang      print('測試圖片:', self.image)      begin = time.time()      async_client.set_task(self.task_func1,self.num,session) # 設置并發任務      async_client.run()  # 執行任務      end=time.time()      self.all_time.sort(reverse=True)      print(self.all_time)      print('并發數量(個):',self.total_num)      print('總耗時(s):',end-begin)      print('最大時延(s):',self.all_time[0])      print('最小時延(s):', self.all_time[len(self.all_time)-1])      print('top-90%時延(s):', self.all_time[int(len(self.all_time)*0.1)])      print('平均耗時(s/個):',sum(self.all_time)/self.total_num)      print('支持并發率(個/s):',self.total_num/(end-begin))      print('總負載(MB):',self.total_payload)      print('吞吐率(MB/S):',self.total_payload/(end-begin))  # 吞吐率受上行下行帶寬,服務器帶寬,服務器算法性能諸多影響      time.sleep(3)    session.close()    print('test finish')

aiohttp服務器mvc(靜態網頁,模板,數據庫,log)

aiohttp之添加靜態資源路徑

所謂靜態資源,是指圖片、js、css等文件。

以一個小項目來說明,下面是項目的目錄結構:

.├── static│  ├── css│  │  ├── base.css│  │  ├── bootstrap.min.css│  │  └── font-awesome.min.css│  ├── font│  │  ├── FontAwesome.otf│  │  ├── fontawesome-webfont.eot│  │  ├── fontawesome-webfont.svg│  │  ├── fontawesome-webfont.ttf│  │  └── fontawesome-webfont.woff│  └── index.html└── proxy_server.py

在proxy_server.py給2個靜態文件目錄static/css和static/font添加路由:

app.router.add_static('/css/',            path='static/css',            name='css')app.router.add_static('/font/',            path='static/font',            name='font')

必需的2個參數:

prefix:是靜態文件的url的前綴,以/開始,在瀏覽器地址欄上顯示在網站host之后,也用于index.html靜態頁面進行引用 
path:靜態文件目錄的路徑,可以是相對路徑,上面代碼使用的static/css就是相對路徑——相對于proxy_server.py所在路徑。

Python,asyncio,aiohttp

加載的是index.html,下面是它引用靜態資源的代碼:

<!-- Bootstrap CSS --><link href="css/bootstrap.min.css" rel="external nofollow" rel="stylesheet"><!-- Base CSS --><link href="css/base.css" rel="external nofollow" rel="stylesheet"><!-- FA CSS --><link href="css/font-awesome.min.css" rel="external nofollow" rel="stylesheet">

添加font的路徑是因為/font-awesome.min.css需要使用:

如果修改前綴:

 app.router.add_static('/css2017/',            path='static/css',            name='css')

雖然目錄本身還是css,但通過add_static已經將它視為了css2017,在文件和瀏覽器中要想鏈接到css下的文件,必須使用css2017/xx.css來鏈接。

此外,如果加上show_index=True,就可以顯示靜態資源的目錄索引了——默認是禁止訪問的:

app.router.add_static('/css2017/',            path='static/css',            name='css',            show_index=True)

Python,asyncio,aiohttp

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到python教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 漳州市| 新郑市| 平罗县| 内乡县| 建昌县| 宾阳县| 周至县| 安阳市| 罗山县| 合肥市| 鄄城县| 永登县| 邹城市| 遂溪县| 突泉县| 合阳县| 长丰县| 景洪市| 卢龙县| 麦盖提县| 山东省| 蓝田县| 西青区| 定南县| 封开县| 邹平县| 同心县| 夹江县| 眉山市| 北安市| 柏乡县| 囊谦县| 德庆县| 山东| 监利县| 石棉县| 湖南省| 渝北区| 长阳| 青川县| 西丰县|