亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python加速程序運行的方法

 更新時間:2020年07月29日 11:04:29   作者:David Beazley  
這篇文章主要介紹了Python加速程序運行的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

問題

你的程序運行太慢,你想在不使用復(fù)雜技術(shù)比如C擴展或JIT編譯器的情況下加快程序運行速度。

解決方案

關(guān)于程序優(yōu)化的第一個準(zhǔn)則是“不要優(yōu)化”,第二個準(zhǔn)則是“不要優(yōu)化那些無關(guān)緊要的部分”。 如果你的程序運行緩慢,首先你得使用14.13小節(jié)的技術(shù)先對它進行性能測試找到問題所在。

通常來講你會發(fā)現(xiàn)你得程序在少數(shù)幾個熱點位置花費了大量時間, 比如內(nèi)存的數(shù)據(jù)處理循環(huán)。一旦你定位到這些點,你就可以使用下面這些實用技術(shù)來加速程序運行。

使用函數(shù)

很多程序員剛開始會使用Python語言寫一些簡單腳本。 當(dāng)編寫腳本的時候,通常習(xí)慣了寫毫無結(jié)構(gòu)的代碼,比如:

# somescript.py

import sys
import csv

with open(sys.argv[1]) as f:
   for row in csv.reader(f):

     # Some kind of processing
     pass

很少有人知道,像這樣定義在全局范圍的代碼運行起來要比定義在函數(shù)中運行慢的多。 這種速度差異是由于局部變量和全局變量的實現(xiàn)方式(使用局部變量要更快些)。 因此,如果你想讓程序運行更快些,只需要將腳本語句放入函數(shù)中即可:

# somescript.py
import sys
import csv

def main(filename):
  with open(filename) as f:
     for row in csv.reader(f):
       # Some kind of processing
       pass

main(sys.argv[1])

速度的差異取決于實際運行的程序,不過根據(jù)經(jīng)驗,使用函數(shù)帶來15-30%的性能提升是很常見的。

盡可能去掉屬性訪問

每一次使用點(.)操作符來訪問屬性的時候會帶來額外的開銷。 它會觸發(fā)特定的方法,比如 __getattribute__() __getattr__() ,這些方法會進行字典操作操作。

通常你可以使用 from module import name 這樣的導(dǎo)入形式,以及使用綁定的方法。 假設(shè)你有如下的代碼片段:

import math

def compute_roots(nums):
  result = []
  for n in nums:
    result.append(math.sqrt(n))
  return result

# Test
nums = range(1000000)
for n in range(100):
  r = compute_roots(nums)

在我們機器上面測試的時候,這個程序花費了大概40秒?,F(xiàn)在我們修改 compute_roots() 函數(shù)如下:

from math import sqrt

def compute_roots(nums):

  result = []
  result_append = result.append
  for n in nums:
    result_append(sqrt(n))
  return result

修改后的版本運行時間大概是29秒。唯一不同之處就是消除了屬性訪問。 用 sqrt() 代替了 math.sqrt() The result.append() 方法被賦給一個局部變量 result_append ,然后在內(nèi)部循環(huán)中使用它。

不過,這些改變只有在大量重復(fù)代碼中才有意義,比如循環(huán)。 因此,這些優(yōu)化也只是在某些特定地方才應(yīng)該被使用。

理解局部變量

之前提過,局部變量會比全局變量運行速度快。 對于頻繁訪問的名稱,通過將這些名稱變成局部變量可以加速程序運行。 例如,看下之前對于 compute_roots() 函數(shù)進行修改后的版本:

import math

def compute_roots(nums):
  sqrt = math.sqrt
  result = []
  result_append = result.append
  for n in nums:
    result_append(sqrt(n))
  return result

在這個版本中,sqrtmath 模塊被拿出并放入了一個局部變量中。 如果你運行這個代碼,大概花費25秒(對于之前29秒又是一個改進)。 這個額外的加速原因是因為對于局部變量 sqrt 的查找要快于全局變量 sqrt

對于類中的屬性訪問也同樣適用于這個原理。 通常來講,查找某個值比如 self.name 會比訪問一個局部變量要慢一些。 在內(nèi)部循環(huán)中,可以將某個需要頻繁訪問的屬性放入到一個局部變量中。例如:

# Slower
class SomeClass:
  ...
  def method(self):
     for x in s:
       op(self.value)

# Faster
class SomeClass:

  ...
  def method(self):
     value = self.value
     for x in s:
       op(value)

避免不必要的抽象

任何時候當(dāng)你使用額外的處理層(比如裝飾器、屬性訪問、描述器)去包裝你的代碼時,都會讓程序運行變慢。 比如看下如下的這個類:

class A:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  @property
  def y(self):
    return self._y
  @y.setter
  def y(self, value):
    self._y = value

現(xiàn)在進行一個簡單測試:

>>> from timeit import timeit
>>> a = A(1,2)
>>> timeit('a.x', 'from __main__ import a')
0.07817923510447145
>>> timeit('a.y', 'from __main__ import a')
0.35766440676525235
>>>

可以看到,訪問屬性y相比屬性x而言慢的不止一點點,大概慢了4.5倍。 如果你在意性能的話,那么就需要重新審視下對于y的屬性訪問器的定義是否真的有必要了。 如果沒有必要,就使用簡單屬性吧。 如果僅僅是因為其他編程語言需要使用getter/setter函數(shù)就去修改代碼風(fēng)格,這個真的沒有必要。

使用內(nèi)置的容器

內(nèi)置的數(shù)據(jù)類型比如字符串、元組、列表、集合和字典都是使用C來實現(xiàn)的,運行起來非???。 如果你想自己實現(xiàn)新的數(shù)據(jù)結(jié)構(gòu)(比如鏈接列表、平衡樹等), 那么要想在性能上達到內(nèi)置的速度幾乎不可能,因此,還是乖乖的使用內(nèi)置的吧。

避免創(chuàng)建不必要的數(shù)據(jù)結(jié)構(gòu)或復(fù)制

有時候程序員想顯擺下,構(gòu)造一些并沒有必要的數(shù)據(jù)結(jié)構(gòu)。例如,有人可能會像下面這樣寫:

values = [x for x in sequence]
squares = [x*x for x in values]

也許這里的想法是首先將一些值收集到一個列表中,然后使用列表推導(dǎo)來執(zhí)行操作。 不過,第一個列表完全沒有必要,可以簡單的像下面這樣寫:

squares = [x*x for x in sequence]

與此相關(guān),還要注意下那些對Python的共享數(shù)據(jù)機制過于偏執(zhí)的程序所寫的代碼。 有些人并沒有很好的理解或信任Python的內(nèi)存模型,濫用 copy.deepcopy() 之類的函數(shù)。 通常在這些代碼中是可以去掉復(fù)制操作的。

討論

在優(yōu)化之前,有必要先研究下使用的算法。 選擇一個復(fù)雜度為 O(n log n) 的算法要比你去調(diào)整一個復(fù)雜度為 O(n**2) 的算法所帶來的性能提升要大得多。

如果你覺得你還是得進行優(yōu)化,那么請從整體考慮。 作為一般準(zhǔn)則,不要對程序的每一個部分都去優(yōu)化,因為這些修改會導(dǎo)致代碼難以閱讀和理解。 你應(yīng)該專注于優(yōu)化產(chǎn)生性能瓶頸的地方,比如內(nèi)部循環(huán)。

你還要注意微小優(yōu)化的結(jié)果。例如考慮下面創(chuàng)建一個字典的兩種方式:

a = {
  'name' : 'AAPL',
  'shares' : 100,
  'price' : 534.22
}

b = dict(name='AAPL', shares=100, price=534.22)

后面一種寫法更簡潔一些(你不需要在關(guān)鍵字上輸入引號)。 不過,如果你將這兩個代碼片段進行性能測試對比時,會發(fā)現(xiàn)使用 dict() 的方式會慢了3倍。 看到這個,你是不是有沖動把所有使用 dict() 的代碼都替換成第一種。 不夠,聰明的程序員只會關(guān)注他應(yīng)該關(guān)注的地方,比如內(nèi)部循環(huán)。在其他地方,這點性能損失沒有什么影響。

如果你的優(yōu)化要求比較高,本節(jié)的這些簡單技術(shù)滿足不了,那么你可以研究下基于即時編譯(JIT)技術(shù)的一些工具。 例如,PyPy工程是Python解釋器的另外一種實現(xiàn),它會分析你的程序運行并對那些頻繁執(zhí)行的部分生成本機機器碼。 它有時候能極大的提升性能,通??梢越咏麮代碼的速度。 不過可惜的是,到寫這本書為止,PyPy還不能完全支持Python3. 因此,這個是你將來需要去研究的。你還可以考慮下Numba工程, Numba是一個在你使用裝飾器來選擇Python函數(shù)進行優(yōu)化時的動態(tài)編譯器。 這些函數(shù)會使用LLVM被編譯成本地機器碼。它同樣可以極大的提升性能。 但是,跟PyPy一樣,它對于Python 3的支持現(xiàn)在還停留在實驗階段。

最后我引用John Ousterhout說過的話作為結(jié)尾:“最好的性能優(yōu)化是從不工作到工作狀態(tài)的遷移”。 直到你真的需要優(yōu)化的時候再去考慮它。確保你程序正確的運行通常比讓它運行更快要更重要一些(至少開始是這樣的).

以上就是Python加速程序運行的方法的詳細(xì)內(nèi)容,更多關(guān)于Python加速程序運行的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 淺談Python xlwings 讀取Excel文件的正確姿勢

    淺談Python xlwings 讀取Excel文件的正確姿勢

    這篇文章主要介紹了淺談Python xlwings 讀取Excel文件的正確姿勢,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Python實現(xiàn)雙進程防止單點故障實例深度探究

    Python實現(xiàn)雙進程防止單點故障實例深度探究

    在分布式系統(tǒng)中,確保系統(tǒng)的高可用性是至關(guān)重要的,本文將深入探討如何使用Python實現(xiàn)雙進程自我保護機制,以應(yīng)對單點故障,確保系統(tǒng)穩(wěn)定運行,將通過詳實的示例代碼,介紹雙進程自我保護的原理、實現(xiàn)步驟以及可能遇到的挑戰(zhàn)
    2024-01-01
  • Python學(xué)習(xí)之名字,作用域,名字空間(下)

    Python學(xué)習(xí)之名字,作用域,名字空間(下)

    這篇文章主要介紹了Python學(xué)習(xí)之名字,作用域,名字空間,緊接上一篇文章內(nèi)容展開全文,需要的小伙伴可以參考一下,希望對你的學(xué)習(xí)有所幫助
    2022-05-05
  • Python序列化模塊之pickle與json詳解

    Python序列化模塊之pickle與json詳解

    這篇文章主要為大家介紹了Python中常用的兩個序列化模塊:pickle序列化和json序列化。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下
    2022-05-05
  • 如何使用python提取字符串的中英文(正則判斷)

    如何使用python提取字符串的中英文(正則判斷)

    這篇文章主要給大家介紹了關(guān)于如何使用python提取字符串中英文的相關(guān)資料,主要通過正則re中的sub函數(shù)、findall函數(shù)以及compile函數(shù)判斷來實現(xiàn),需要的朋友可以參考下
    2021-05-05
  • Python如何根據(jù)關(guān)鍵字逐行提取文本內(nèi)容問題

    Python如何根據(jù)關(guān)鍵字逐行提取文本內(nèi)容問題

    這篇文章主要介紹了Python如何根據(jù)關(guān)鍵字逐行提取文本內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 詳解Python中對Excel的處理操作

    詳解Python中對Excel的處理操作

    Excel是一種常見的電子表格文件格式,廣泛用于數(shù)據(jù)記錄和處理,Python提供了多個第三方庫,可以方便地對Excel操作,下面就來和大家詳細(xì)講講吧
    2023-07-07
  • python3實現(xiàn)往mysql中插入datetime類型的數(shù)據(jù)

    python3實現(xiàn)往mysql中插入datetime類型的數(shù)據(jù)

    這篇文章主要介紹了python3實現(xiàn)往mysql中插入datetime類型的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • python dict.get()和dict[''key'']的區(qū)別詳解

    python dict.get()和dict[''key'']的區(qū)別詳解

    下面小編就為大家?guī)硪黄猵ython dict.get()和dict['key']的區(qū)別詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • Python實現(xiàn)的端口掃描功能示例

    Python實現(xiàn)的端口掃描功能示例

    這篇文章主要介紹了Python實現(xiàn)的端口掃描功能,涉及Python針對端口的連接、打開、關(guān)閉及線程相關(guān)操作技巧,需要的朋友可以參考下
    2018-04-04

最新評論