最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

提升python處理速度原理及方法實(shí)例

 更新時(shí)間:2019年12月25日 10:42:03   作者:夏末蟬未鳴  
這篇文章主要介紹了提升python處理速度原理及方法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了提升python處理速度原理及方法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

 導(dǎo)讀:作為日常生產(chǎn)開發(fā)中非常實(shí)用的一門語言,python廣泛應(yīng)用于網(wǎng)絡(luò)爬蟲、web開發(fā)、自動(dòng)化測試、數(shù)據(jù)分析和人工智能等領(lǐng)域。但python是單線程的,想要提升python的處理速度,涉及到一個(gè)很關(guān)鍵的技術(shù)——協(xié)程。本篇文章,將講述python協(xié)程的理解與使用。

1、操作系統(tǒng)相關(guān)概念

  在理解與使用協(xié)程之前,先簡單的了解幾個(gè)與操作系統(tǒng)相關(guān)的概念,包括進(jìn)程、線程、同步和異步、阻塞與非阻塞。了解這些概念,對(duì)你學(xué)習(xí)協(xié)程、消息隊(duì)列、緩存等知識(shí)都有一定的幫助。

(1)進(jìn)程:

  進(jìn)程是操作系統(tǒng)分配資源的最小單位,系統(tǒng)由一個(gè)個(gè)程序(進(jìn)程)組成的,一般而言,分為文本區(qū)域、數(shù)據(jù)區(qū)域和堆棧區(qū)域

  文本區(qū)域存儲(chǔ)處理器執(zhí)行的代碼(機(jī)器碼),通常來說,這是一個(gè)只讀區(qū)域,防止運(yùn)行的程序被意外的修改

  數(shù)據(jù)區(qū)域存儲(chǔ)所有的變量和動(dòng)態(tài)分配的內(nèi)存,又細(xì)分為初始化的數(shù)據(jù)區(qū)(所有初始化的全局、靜態(tài)、常量以及外部變量)和未初始化的數(shù)據(jù)區(qū)(初始化未0的全局變量和靜態(tài)變量),初始化的變量最初保存在文本區(qū),程序啟動(dòng)后被拷貝到初始化的數(shù)據(jù)區(qū)

  堆棧區(qū)域存儲(chǔ)著活動(dòng)過程調(diào)用的指令和本地變量,在地址空間里,棧區(qū)緊連著堆區(qū),他們的增長方向相反,內(nèi)存是線性的,所以我們的代碼放在低地址的地方,由低向高增長,棧區(qū)大小不可預(yù)測,隨開隨用,因此放在高地址的地方,由高向低增長。當(dāng)堆與棧指針重合的時(shí)候,意味著內(nèi)存耗盡,造成內(nèi)存溢出。

  進(jìn)程的創(chuàng)建和銷毀都非常的消耗系統(tǒng)資源,是一種比較昂貴的操作。進(jìn)程為了自身能夠得到運(yùn)行,必須搶占式的爭奪CPU。對(duì)于單核CPU而言,在同一時(shí)間內(nèi)只能執(zhí)行一個(gè)進(jìn)程的代碼,所以在單核CPU上實(shí)現(xiàn)多進(jìn)程,是通過CPU的快速切換不同進(jìn)程來實(shí)現(xiàn)的,看上去就像是多個(gè)進(jìn)程同時(shí)執(zhí)行。

  由于進(jìn)程間是隔離的,各自擁有自己的內(nèi)存資源,相比于線程的共享內(nèi)存而言,要更安全,不同進(jìn)程之間的數(shù)據(jù)只能通過IPC(Inter-Process Communication)進(jìn)行通信共享

(2)線程

  線程是CPU調(diào)度的基本單位。如果進(jìn)程是一個(gè)容器,線程就是運(yùn)行在容器里面的程序,線程是屬于進(jìn)程的,同個(gè)進(jìn)程的多個(gè)線程共享進(jìn)程的內(nèi)存地址空間

  線程間可以直接通過全局變量進(jìn)行通信,所以相對(duì)來說,線程間通信是不太安全的,因此引入各種鎖的場景,這里將不闡述

  當(dāng)一個(gè)線程奔潰了,會(huì)導(dǎo)致整個(gè)進(jìn)程也奔潰,即其它線程也掛了。這一點(diǎn)與進(jìn)程不一樣,一個(gè)進(jìn)程掛了,其他進(jìn)程照樣執(zhí)行

  在多核操作系統(tǒng)中,默認(rèn)一個(gè)進(jìn)程內(nèi)只有一個(gè)線程,所以對(duì)多進(jìn)程處理就像是一個(gè)進(jìn)程一個(gè)核心

(3)同步和異步

  同步和異步關(guān)注的是消息通信機(jī)制,所謂同步,就是在發(fā)出一個(gè)函數(shù)調(diào)用時(shí),在沒有得到結(jié)果之前,該調(diào)用不會(huì)返回。一旦調(diào)用返回,就立即得到調(diào)用的返回值,即調(diào)用者主動(dòng)等待調(diào)用結(jié)果

  所謂異步,就是在請(qǐng)求發(fā)出去后,這個(gè)調(diào)用就立即返回,但沒有返回結(jié)果,通過回調(diào)的方式告知該調(diào)用的實(shí)際結(jié)果

  同步的請(qǐng)求,需要主動(dòng)讀寫數(shù)據(jù),并且等待結(jié)果;異步的請(qǐng)求,調(diào)用者不會(huì)立即得到結(jié)果。而是在調(diào)用發(fā)出后,被調(diào)用者通過狀態(tài)、通知來告訴調(diào)用者,或通過回調(diào)函數(shù)處理這個(gè)調(diào)用

(4)阻塞與非阻塞

  阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息,返回值)時(shí)的狀態(tài)

  阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回

  非阻塞調(diào)用指在得到不能立即得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程。所以,區(qū)分的條件在于,進(jìn)程/線程要訪問的數(shù)據(jù)是否就緒,進(jìn)程/線程是否需要等待

  非阻塞一般通過多路復(fù)用實(shí)現(xiàn),多路復(fù)用由select、poll、epoll幾種實(shí)現(xiàn)方式

(5)協(xié)程

  了解完前面幾個(gè)概念,再來看看協(xié)程的概念

  協(xié)程是屬于線程的,又稱微線程,纖程,英文名是coroutine。舉個(gè)例子,在執(zhí)行函數(shù)A時(shí),我希望能隨時(shí)終端去執(zhí)行函數(shù)B,然后終端B的執(zhí)行,切換回來執(zhí)行函數(shù)A。這就是協(xié)程的作用,由調(diào)用者自有切換。這個(gè)切換過程并不等同于函數(shù)調(diào)用,因?yàn)樗鼪]有調(diào)用語句。執(zhí)行方式與多線程類似,但是協(xié)程只有一個(gè)線程執(zhí)行

  協(xié)程的優(yōu)點(diǎn)是執(zhí)行效率非常高,因?yàn)閰f(xié)程的切換是由程序自身控制,不需要切換線程,即沒有切換線程的開銷。同時(shí),由于只有一個(gè)線程,不存在沖突的問題,不需要依賴鎖(加鎖和釋放鎖需要很多資源消耗)

  協(xié)程的主要使用場景在于處理io密集型程序,解決效率問題,不同于CPU密集型程序的處理。然而實(shí)際開發(fā)中這兩種場景非常多,如果要充分發(fā)揮CPU的利用率,可以使用多進(jìn)程+協(xié)程的方式,本文后續(xù)將講到結(jié)合點(diǎn)

2、協(xié)程相關(guān)原理

  根據(jù)wikipedia的定義,協(xié)程是一個(gè)無優(yōu)先級(jí)的子程序調(diào)度組件,允許子程序在特定的地方掛起恢復(fù)。所以理論上,只要內(nèi)存足夠,一個(gè)線程可以有任意多個(gè)協(xié)程,但同一時(shí)刻只能有一個(gè)協(xié)程在運(yùn)行,多個(gè)協(xié)程分享該線程分配到的計(jì)算機(jī)資源。協(xié)程是為了充分發(fā)揮異步調(diào)用的優(yōu)勢,異步操作則是為了IO操作阻塞線程

(1)知識(shí)準(zhǔn)備

  在了解原理前,先做一個(gè)知識(shí)的準(zhǔn)備

  1)現(xiàn)代主流的操作系統(tǒng)幾乎都是分時(shí)操作系統(tǒng),即一臺(tái)計(jì)算機(jī)采用時(shí)間片輪轉(zhuǎn)的方式為多個(gè)用戶提供服務(wù),系統(tǒng)資源分配的基本單位是進(jìn)程,CPU調(diào)度的基本單位是線程

  2)運(yùn)行時(shí)內(nèi)存空間氛圍變量區(qū)、棧區(qū)、堆區(qū)。內(nèi)存地址分配上,堆區(qū)從低到高,棧區(qū)從高到低

  3)計(jì)算機(jī)執(zhí)行時(shí)一條條指令讀取執(zhí)行,執(zhí)行到當(dāng)前指令時(shí),下一條指令的指令的地址在指令寄存器的IP中,ESP寄存值只想當(dāng)前棧頂?shù)刂罚珽BP指向當(dāng)前活動(dòng)棧幀的基地址

  4)系統(tǒng)發(fā)生函數(shù)調(diào)用時(shí)操作為:先將入?yún)挠彝笠淮螇簵#缓蟀逊祷氐刂穳簵?,最后將?dāng)前EBP寄存器的值壓棧,修改ESP寄存器的值,在棧區(qū)分配當(dāng)前函數(shù)局部變量所需的空間

  5)協(xié)程的上下文包含屬于當(dāng)前協(xié)程的棧區(qū)和寄存器里面存放的值

(2)事件循環(huán)

  在python3.3中通過yield from使用協(xié)程,在3.5中,引入了關(guān)于協(xié)程的語法糖async/await的原理解析。其中,事件循環(huán)是一個(gè)核心所在,編寫過js的同學(xué),會(huì)對(duì)事件循環(huán)Eventloop更加了解,事件循環(huán)是一種等待程序分配消息或事件的編程架構(gòu)。在python中,asyncio.coroutine修飾器用來標(biāo)記作為協(xié)程的函數(shù),這里的協(xié)程是和asyncio及其事件循環(huán)一起使用的,而在后續(xù)的發(fā)展中,async/await被使用的越來越廣泛

(3)async/await

  async/await是使用python協(xié)程的關(guān)鍵,從結(jié)構(gòu)上來看,asyncio實(shí)質(zhì)上是一個(gè)異步框架,async/await是為異步框架提供API以方便使用者調(diào)用,所以使用者要想使用async/await編寫協(xié)程代碼,目前必須基于asyncio或其他異步庫

(4)Future

  在實(shí)際開發(fā)編寫異步代碼時(shí),為了避免太多回調(diào)方法導(dǎo)致的回調(diào)地獄,但又需要獲取異步調(diào)用的返回結(jié)果,聰明的語言設(shè)計(jì)者設(shè)計(jì)了一個(gè)叫做Future的對(duì)象,封裝了與loop的交互行為。其大致執(zhí)行過程為:程序啟動(dòng)后,通過add_done_callback方法向epoll注冊(cè)回調(diào)函數(shù),當(dāng)result屬性得到返回值后,主動(dòng)運(yùn)行之前注冊(cè)的回調(diào)函數(shù),向上傳遞給coroutine。這個(gè)Future對(duì)象為asyncio.Future

  但是,要想取得返回值,程序必須恢復(fù)到工作狀態(tài),而由于Future對(duì)象本身的生存周期比較短,每一次注冊(cè)回調(diào)、產(chǎn)生事件、觸發(fā)回調(diào)過程后工作可能已經(jīng)完成,所以用Future向生成器send result并不合適。這里又引入一個(gè)新的對(duì)象Task,保存在Future對(duì)象中,對(duì)生成器協(xié)程進(jìn)行狀態(tài)管理

  Python里另一個(gè)Future對(duì)象是concurrent.futures.Future,與asyncio.Future互不兼容,容易產(chǎn)生混淆。區(qū)別點(diǎn)在于,concurrent.futures是線程級(jí)的Future對(duì)象,當(dāng)使用concurrent.futures.Executor進(jìn)行多線程編程時(shí),該對(duì)象用于在不同的thread之間傳遞結(jié)果

(5)Task

  上文中提到,Task是維護(hù)生成器協(xié)程狀態(tài)處理執(zhí)行邏輯的任務(wù)對(duì)象,Task中有一個(gè)_step方法,負(fù)責(zé)生成器協(xié)程與EventLoop交互過程的狀態(tài)遷移,整個(gè)過程可以理解為:Task向協(xié)程send一個(gè)值,恢復(fù)其工作狀態(tài)。當(dāng)協(xié)程運(yùn)行到斷點(diǎn)后,得到新的Future對(duì)象,再處理future與loop的回調(diào)注冊(cè)過程

(6)Loop

  在日常開發(fā)中,會(huì)有一個(gè)誤區(qū),認(rèn)為每一個(gè)線程都可以有一個(gè)獨(dú)立的loop。實(shí)際運(yùn)行時(shí),主線程才能通過asyncio.get_event_loop()創(chuàng)建一個(gè)新的loop,而在其他線程時(shí),使用get_event_loop()卻會(huì)拋錯(cuò)。正確的做法為通過asyncio.set_event_loop(),將當(dāng)前線程與主線程loop顯式綁定

3、協(xié)程實(shí)戰(zhàn)

  上面介紹完了協(xié)程相關(guān)的概念和原理,接下來看看如何使用,這里舉一個(gè)實(shí)際場景的例子

場景:
  外部接受一些文件,每個(gè)文件里有一些數(shù)據(jù),其中,這組數(shù)據(jù)需要通過http的方式,發(fā)向第三方平臺(tái),并獲得結(jié)果

分析:
  由于同一文件的每一組數(shù)據(jù)沒有前后的處理邏輯,在之前通過requests庫發(fā)送的網(wǎng)絡(luò)請(qǐng)求,串行執(zhí)行,下一組數(shù)據(jù)的發(fā)送需要等待上一組數(shù)據(jù)的返回,顯得整個(gè)文件的處理時(shí)間長,這種請(qǐng)求方式,完全可以由協(xié)程來實(shí)現(xiàn)

  為了更方便的配合協(xié)程發(fā)請(qǐng)求,我們使用aiohttp庫來代替requests庫,關(guān)于aiohttp,下面做簡單介紹

aiohttp:

  aiohttp是asyncio和python的異步HTTP客戶端/服務(wù)器,由于是異步的,經(jīng)常用在服務(wù)器端接收請(qǐng)求,和客戶端爬蟲應(yīng)用,發(fā)起異步請(qǐng)求,這里我們主要用來發(fā)請(qǐng)求

  aiohttp支持客戶端和HTTP服務(wù)器,可以實(shí)現(xiàn)單線程并發(fā)IO操作,無需使用Callback Hell即可支持Server WebSockets和Client WebSockets,且具有中間件

4、代碼實(shí)現(xiàn)

直接上代碼吧,talk is cheap,show me the code~

import aiohttp
import asyncio
from inspect import isfunction
import time
import logger

@logging_utils.exception(logger)
def request(pool, data_list):
  loop = asyncio.get_event_loop()
  loop.run_until_complete(exec(pool, data_list))
async def exec(pool, data_list):
  tasks = []
  sem = asyncio.Semaphore(pool)
  for item in data_list:
    tasks.append(
      control_sem(sem,
            item.get("method", "GET"),
            item.get("url"),
            item.get("data"),
            item.get("headers"),
            item.get("callback")))
  await asyncio.wait(tasks)
async def control_sem(sem, method, url, data, headers, callback):
  async with sem:
    count = 0
    flag = False
    while not flag and count < 4:
      flag = await fetch(method, url, data, headers, callback)
      count = count + 1
      print("flag:{},count:{}".format(flag, count))
    if count == 4 and not flag:
      raise Exception('EAS service not responding after 4 times of retry.')
async def fetch(method, url, data, headers, callback):
  async with aiohttp.request(method, url=url, data=data, headers=headers) as resp:
    try:
      json = await resp.read()
      print(json)
      if resp.status != 200:
        return False
      if isfunction(callback):
        callback(json)
      return True
    except Exception as e:
      print(e)

這里,我們封裝了對(duì)外發(fā)送批量請(qǐng)求的request方法,接收一次性發(fā)送的數(shù)據(jù)多少,和數(shù)據(jù)綜合,在外部使用時(shí),只需要構(gòu)建好網(wǎng)絡(luò)請(qǐng)求對(duì)象的數(shù)據(jù),設(shè)定好請(qǐng)求池大小即可,同時(shí),設(shè)置了重試功能,進(jìn)行了4次重試,防治在網(wǎng)絡(luò)抖動(dòng)的時(shí)候,單個(gè)數(shù)據(jù)的網(wǎng)絡(luò)請(qǐng)求發(fā)送失敗

最終效果:

在使用協(xié)程重構(gòu)網(wǎng)絡(luò)請(qǐng)求模塊之后,當(dāng)數(shù)據(jù)量在1000的時(shí)候,由之前的816s,提升到424s,快了一倍,且請(qǐng)求池大小加大的時(shí)候,效果更明顯,由于第三方平臺(tái)同時(shí)建立連接的數(shù)據(jù)限制,我們?cè)O(shè)定了40的閾值??梢钥吹剑瑑?yōu)化的程度很顯著

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決安裝pycharm后不能執(zhí)行python腳本的問題

    解決安裝pycharm后不能執(zhí)行python腳本的問題

    今天小編就為大家分享一篇解決安裝pycharm后不能執(zhí)行python腳本的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • python程序超時(shí)處理方式

    python程序超時(shí)處理方式

    這篇文章主要介紹了python程序超時(shí)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • python與js主要區(qū)別點(diǎn)總結(jié)

    python與js主要區(qū)別點(diǎn)總結(jié)

    在本篇內(nèi)容里小編給大家整理了關(guān)于python與js主要區(qū)別點(diǎn)總結(jié)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2020-09-09
  • Python如何存儲(chǔ)和讀取ASCII碼形式的byte數(shù)據(jù)

    Python如何存儲(chǔ)和讀取ASCII碼形式的byte數(shù)據(jù)

    這篇文章主要介紹了Python如何存儲(chǔ)和讀取ASCII碼形式的byte數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • 一文帶你深入理解Python魔法方法

    一文帶你深入理解Python魔法方法

    在Python中,魔法方法是指那些以雙下劃線開頭和結(jié)尾的特殊方法,它們是Python的內(nèi)置方法,對(duì)應(yīng)于Python對(duì)象的各種運(yùn)算符,這篇文章將深入探討Python的一些魔法方法,并通過示例展示如何使用它們,需要的朋友可以參考下
    2023-06-06
  • Python中bytes和str的區(qū)別與聯(lián)系詳解

    Python中bytes和str的區(qū)別與聯(lián)系詳解

    Python3最重要的新特性之一是對(duì)字符串和二進(jìn)制數(shù)據(jù)流做了明確的區(qū),下面這篇文章主要給大家介紹了關(guān)于Python中bytes和str區(qū)別與聯(lián)系的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • Linux下python3.6.1環(huán)境配置教程

    Linux下python3.6.1環(huán)境配置教程

    這篇文章主要為大家詳細(xì)介紹了Linux下python3.6.1環(huán)境配置教程 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Python數(shù)據(jù)可視化之Seaborn的使用詳解

    Python數(shù)據(jù)可視化之Seaborn的使用詳解

    Seaborn庫是python中基于matplotlib庫的可視化工具庫,通過sns我們可以更方便地繪制出更美觀的圖表。本文將分享python基于Seaborn庫的一系列繪圖操作,感興趣的可以了解一下
    2022-04-04
  • python tkinter模塊的簡單使用

    python tkinter模塊的簡單使用

    這篇文章主要介紹了python tkinter模塊的簡單使用,幫助大家更好的理解和學(xué)習(xí)使用python制作gui界面,感興趣的朋友可以了解下
    2021-04-04
  • Python模塊Typing.overload的使用場景分析

    Python模塊Typing.overload的使用場景分析

    在 Python 中,typing.overload 是一個(gè)用于定義函數(shù)重載的裝飾器,函數(shù)重載是指在一個(gè)類中可以定義多個(gè)相同名字但參數(shù)不同的函數(shù),使得在調(diào)用函數(shù)時(shí)可以根據(jù)參數(shù)的不同選擇不同的函數(shù)執(zhí)行,這篇文章主要介紹了Python模塊Typing.overload的使用,需要的朋友可以參考下
    2024-02-02

最新評(píng)論

琼海市| 利辛县| 巴中市| 克什克腾旗| 东海县| 前郭尔| 嘉义市| 巨鹿县| 陆河县| 宁海县| 铜山县| 清远市| 乌什县| 莱州市| 丰顺县| 长治市| 沙洋县| 马公市| 长海县| 巴青县| 彩票| 隆昌县| 北流市| 泽普县| 英德市| 左权县| 广宁县| 泰和县| 桃园县| 清丰县| 响水县| 潜江市| 神池县| 缙云县| 新巴尔虎右旗| 繁峙县| 周宁县| 开封县| 博湖县| 重庆市| 确山县|