中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

利用Python如何實現異步IO操作

發布時間:2020-11-06 14:52:48 來源:億速云 閱讀:172 作者:Leah 欄目:開發技術

本篇文章給大家分享的是有關利用Python如何實現異步IO操作,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

前言

  用阻塞 API 寫同步代碼最簡單,但一個線程同一時間只能處理一個請求,有限的線程數導致無法實現萬級別的并發連接,過多的線程切換也搶走了 CPU 的時間,從而降低了每秒能夠處理的請求數量。為了達到高并發,你可能會選擇一個異步框架,用非阻塞 API 把業務邏輯打亂到多個回調函數,通過多路復用與事件循環的方式實現高并發。

磁盤 IO 為例,描述了多線程中使用阻塞方法讀磁盤,2 個線程間的切換方式。那么,怎么才能實現高并發呢?

利用Python如何實現異步IO操作

把上圖中本來由內核實現的請求切換工作,交由用戶態的代碼來完成就可以了,異步化編程通過應用層代碼實現了請求切換,降低了切換成本和內存占用空間。異步化依賴于 IO 多路復用機制,比如 Linux 的 epoll 或者 Windows 上的 iocp,同時,必須把阻塞方法更改為非阻塞方法,才能避免內核切換帶來的巨大消耗。Nginx、Redis 等高性能服務都依賴異步化實現了百萬量級的并發。

下圖描述了異步 IO 的非阻塞讀和異步框架結合后,是如何切換請求的。

利用Python如何實現異步IO操作

然而,寫異步化代碼很容易出錯。因為所有阻塞函數,都需要通過非阻塞的系統調用拆分成兩個函數。雖然這兩個函數共同完成一個功能,但調用方式卻不同。第一個函數由你顯式調用,第二個函數則由多路復用機制調用。

這種方式違反了軟件工程的內聚性原則,函數間同步數據也更復雜。特別是條件分支眾多、涉及大量系統調用時,異步化的改造工作會非常困難。

Python如何實現異步調用

from flask import Flask
import time
app = Flask(__name__)


@app.route('/bar')
def bar():
  time.sleep(1)
  return '<h2>bar!</h2>'

@app.route('/foo')
def foo():
  time.sleep(1)
  return '<h2>foo!</h2>'
if __name__ == '__main__':
  app.run(host='127.0.0.1',port=5555,debug=True)

采用同步的方式調用

import requests
import time

starttime = time.time()
print(requests.get('http://127.0.0.1:5555/bar').content)
print(requests.get('http://127.0.0.1:5555/foo').content)
print("消耗時間: ",time.time() -starttime)

b'<h2>bar!</h2>'
b'<h2>foo!</h2>'
消耗時間:  2.015509605407715

采樣異步的方式調用:

重點:

1.將阻塞io改為非阻塞io;

2.多路復用io監聽內核事件,事件觸發通過回調函數;

3.用戶態代碼采取事件循環的方式獲取事件,執行事件的回調函數;

import selectors
import socket
import time
# from asynrequest import ParserHttp
class asynhttp:
  def __init__(self):
    self.selecter = selectors.DefaultSelector()

  def get(self,url,optiondict = None):
    global reqcount
    reqcount += 1
    s = socket.socket()
    s.setblocking(False)
    try:
      s.connect(('127.0.0.1',5555))
    except BlockingIOError:
      pass
    requset = 'GET %s HTTP/1.0\r\n\r\n' % url
    callback = lambda : self.send(s,requset)
    self.selecter.register(s.fileno(),selectors.EVENT_WRITE,callback)

  def send(self,s,requset):
    self.selecter.unregister(s.fileno())
    s.send(requset.encode())
    chunks = []
    callback = lambda: self.recv(s,chunks)
    self.selecter.register(s.fileno(),selectors.EVENT_READ,callback)

  def recv(self,s,chunks):
    self.selecter.unregister(s.fileno())
    chunk = s.recv(1024)
    if chunk:
      chunks.append(chunk)
      callback = lambda: self.recv(s,chunks)
      self.selecter.register(s.fileno(), selectors.EVENT_READ, callback)
    else:
      global reqcount
      reqcount -= 1
      request_first,request_headers,request_content,_ = ParserHttp.parser(b''.join(chunks))
      print("解析數據:",request_first,request_headers,request_content)
      print((b''.join(chunks)).decode())
      return (b''.join(chunks)).decode()

starttime = time.time()
reqcount = 0
asynhttper = asynhttp()
asynhttper.get('/bar')
asynhttper.get('/foo')
while reqcount:
  events = asynhttper.selecter.select()
  for event,mask in events:
    func = event.data
    func()
print("消耗時間:" ,time.time() - starttime)

HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Thu, 15 Oct 2020 03:28:16 GMT

<h2>bar!</h2>
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Thu, 15 Oct 2020 03:28:16 GMT

<h2>foo!</h2>
消耗時間: 1.0127637386322021

以上就是利用Python如何實現異步IO操作,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

轮台县| 天全县| 蒙城县| 天峻县| 左云县| 盐池县| 尉氏县| 阿拉善盟| 伊吾县| 龙川县| 晋江市| 融水| 鹤壁市| 阿图什市| 宁乡县| 秦安县| 翁源县| 陆丰市| 中方县| 屏山县| 五指山市| 厦门市| 连江县| 高青县| 拉孜县| 珠海市| 杨浦区| 平遥县| 军事| 浪卡子县| 宁强县| 东莞市| 大安市| 卢龙县| 丰宁| 麻江县| 新安县| 苏尼特右旗| 黄梅县| 云林县| 灵璧县|