成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

加速Python循環(huán)的12種方法,最高可以提速900倍

開(kāi)發(fā) 前端
在本文中,我將介紹一些簡(jiǎn)單的方法,可以將Python for循環(huán)的速度提高1.3到900倍。

在本文中,我將介紹一些簡(jiǎn)單的方法,可以將Python for循環(huán)的速度提高1.3到900倍。

Python內(nèi)建的一個(gè)常用功能是timeit模塊。下面幾節(jié)中我們將使用它來(lái)度量循環(huán)的當(dāng)前性能和改進(jìn)后的性能。

對(duì)于每種方法,我們通過(guò)運(yùn)行測(cè)試來(lái)建立基線,該測(cè)試包括在10次測(cè)試運(yùn)行中運(yùn)行被測(cè)函數(shù)100K次(循環(huán)),然后計(jì)算每個(gè)循環(huán)的平均時(shí)間(以納秒為單位,ns)。

幾個(gè)簡(jiǎn)單方法

1、列表推導(dǎo)式

# Baseline version (Inefficient way)
 # Calculating the power of numbers
 # Without using List Comprehension
 def test_01_v0(numbers):
   output = []
   for n in numbers:
       output.append(n ** 2.5)
   return output
 
 # Improved version
 # (Using List Comprehension)
 def test_01_v1(numbers):
   output = [n ** 2.5 for n in numbers]
   return output

結(jié)果如下:

# Summary Of Test Results
      Baseline: 32.158 ns per loop
      Improved: 16.040 ns per loop
 % Improvement: 50.1 %
      Speedup: 2.00x

可以看到使用列表推導(dǎo)式可以得到2倍速的提高

2、在外部計(jì)算長(zhǎng)度

如果需要依靠列表的長(zhǎng)度進(jìn)行迭代,請(qǐng)?jiān)趂or循環(huán)之外進(jìn)行計(jì)算。

# Baseline version (Inefficient way)
 # (Length calculation inside for loop)
 def test_02_v0(numbers):
   output_list = []
   for i in range(len(numbers)):
     output_list.append(i * 2)
   return output_list
 
 # Improved version
 # (Length calculation outside for loop)
 def test_02_v1(numbers):
   my_list_length = len(numbers)
   output_list = []
   for i in range(my_list_length):
     output_list.append(i * 2)
   return output_list

通過(guò)將列表長(zhǎng)度計(jì)算移出for循環(huán),加速1.6倍,這個(gè)方法可能很少有人知道吧。

# Summary Of Test Results
      Baseline: 112.135 ns per loop
      Improved: 68.304 ns per loop
 % Improvement: 39.1 %
      Speedup: 1.64x

3、使用Set

在使用for循環(huán)進(jìn)行比較的情況下使用set。

# Use for loops for nested lookups
 def test_03_v0(list_1, list_2):
   # Baseline version (Inefficient way)
   # (nested lookups using for loop)
   common_items = []
   for item in list_1:
       if item in list_2:
           common_items.append(item)
   return common_items
 
 def test_03_v1(list_1, list_2):
   # Improved version
   # (sets to replace nested lookups)
   s_1 = set(list_1)
   s_2 = set(list_2)
   output_list = []
   common_items = s_1.intersection(s_2)
   return common_items

在使用嵌套for循環(huán)進(jìn)行比較的情況下,使用set加速498x

# Summary Of Test Results
      Baseline: 9047.078 ns per loop
      Improved:   18.161 ns per loop
 % Improvement: 99.8 %
      Speedup: 498.17x

4、跳過(guò)不相關(guān)的迭代

避免冗余計(jì)算,即跳過(guò)不相關(guān)的迭代。

# Example of inefficient code used to find 
 # the first even square in a list of numbers
 def function_do_something(numbers):
   for n in numbers:
     square = n * n
     if square % 2 == 0:
         return square
 
   return None  # No even square found
 
 # Example of improved code that 
 # finds result without redundant computations
 def function_do_something_v1(numbers):
   even_numbers = [i for n in numbers if n%2==0]
   for n in even_numbers:
     square = n * n
     return square
 
   return None  # No even square found

這個(gè)方法要在設(shè)計(jì)for循環(huán)內(nèi)容的時(shí)候進(jìn)行代碼設(shè)計(jì),具體能提升多少可能根據(jù)實(shí)際情況不同:

# Summary Of Test Results
      Baseline: 16.912 ns per loop
      Improved: 8.697 ns per loop
 % Improvement: 48.6 %
      Speedup: 1.94x

5、代碼合并

在某些情況下,直接將簡(jiǎn)單函數(shù)的代碼合并到循環(huán)中可以提高代碼的緊湊性和執(zhí)行速度。

# Example of inefficient code
 # Loop that calls the is_prime function n times.
 def is_prime(n):
   if n <= 1:
     return False
   for i in range(2, int(n**0.5) + 1):
     if n % i == 0:
       return False
 
   return True
 
 def test_05_v0(n):
   # Baseline version (Inefficient way)
   # (calls the is_prime function n times)
   count = 0
   for i in range(2, n + 1):
     if is_prime(i):
       count += 1
   return count
 
 def test_05_v1(n):
   # Improved version
   # (inlines the logic of the is_prime function)
   count = 0
   for i in range(2, n + 1):
     if i <= 1:
       continue
     for j in range(2, int(i**0.5) + 1):
       if i % j == 0:
         break
     else:
       count += 1
   return count

這樣也可以提高1.3倍

# Summary Of Test Results
      Baseline: 1271.188 ns per loop
      Improved: 939.603 ns per loop
 % Improvement: 26.1 %
      Speedup: 1.35x

這是為什么呢?

調(diào)用函數(shù)涉及開(kāi)銷,例如在堆棧上推入和彈出變量、函數(shù)查找和參數(shù)傳遞。當(dāng)一個(gè)簡(jiǎn)單的函數(shù)在循環(huán)中被重復(fù)調(diào)用時(shí),函數(shù)調(diào)用的開(kāi)銷會(huì)增加并影響性能。所以將函數(shù)的代碼直接內(nèi)聯(lián)到循環(huán)中可以消除這種開(kāi)銷,從而可能顯著提高速度。

??但是這里需要注意,平衡代碼可讀性和函數(shù)調(diào)用的頻率是一個(gè)要考慮的問(wèn)題。

一些小技巧

6.避免重復(fù)

考慮避免重復(fù)計(jì)算,其中一些計(jì)算可能是多余的,并且會(huì)減慢代碼的速度。相反,在適用的情況下考慮預(yù)計(jì)算。

def test_07_v0(n):
   # Example of inefficient code
   # Repetitive calculation within nested loop
   result = 0
   for i in range(n):
     for j in range(n):
       result += i * j
   return result
 
 def test_07_v1(n):
   # Example of improved code
   # Utilize precomputed values to help speedup
   pv = [[i * j for j in range(n)] for i in range(n)]
   result = 0
   for i in range(n):
     result += sum(pv[i][:i+1])
   return result

結(jié)果如下

# Summary Of Test Results
      Baseline: 139.146 ns per loop
      Improved: 92.325 ns per loop
 % Improvement: 33.6 %
      Speedup: 1.51x

7、使用Generators

生成器支持延遲求值,也就是說(shuō),只有當(dāng)你向它請(qǐng)求下一個(gè)值時(shí),里面的表達(dá)式才會(huì)被求值,動(dòng)態(tài)處理數(shù)據(jù)有助于減少內(nèi)存使用并提高性能。尤其是大型數(shù)據(jù)集中

def test_08_v0(n):
   # Baseline version (Inefficient way)
   # (Inefficiently calculates the nth Fibonacci
   # number using a list)
   if n <= 1:
     return n
   f_list = [0, 1]
   for i in range(2, n + 1):
     f_list.append(f_list[i - 1] + f_list[i - 2])
   return f_list[n]
 
 def test_08_v1(n):
   # Improved version
   # (Efficiently calculates the nth Fibonacci
   # number using a generator)
   a, b = 0, 1
   for _ in range(n):
     yield a
     a, b = b, a + b

可以看到提升很明顯:

# Summary Of Test Results
      Baseline: 0.083 ns per loop
      Improved: 0.004 ns per loop
 % Improvement: 95.5 %
      Speedup: 22.06x

8、map()函數(shù)

使用Python內(nèi)置的map()函數(shù)。它允許在不使用顯式for循環(huán)的情況下處理和轉(zhuǎn)換可迭代對(duì)象中的所有項(xiàng)。

def some_function_X(x):
   # This would normally be a function containing application logic
   # which required it to be made into a separate function
   # (for the purpose of this test, just calculate and return the square)
   return x**2
 
 def test_09_v0(numbers):
   # Baseline version (Inefficient way)
   output = []
   for i in numbers:
     output.append(some_function_X(i))
 
   return output
 
 def test_09_v1(numbers):
   # Improved version
   # (Using Python's built-in map() function)
   output = map(some_function_X, numbers)
   return output

使用Python內(nèi)置的map()函數(shù)代替顯式的for循環(huán)加速了970x。

# Summary Of Test Results
      Baseline: 4.402 ns per loop
      Improved: 0.005 ns per loop
 % Improvement: 99.9 %
      Speedup: 970.69x

這是為什么呢?

map()函數(shù)是用C語(yǔ)言編寫(xiě)的,并且經(jīng)過(guò)了高度優(yōu)化,因此它的內(nèi)部隱含循環(huán)比常規(guī)的Python for循環(huán)要高效得多。因此速度加快了,或者可以說(shuō)Python還是太慢,哈。

9、使用Memoization

記憶優(yōu)化算法的思想是緩存(或“記憶”)昂貴的函數(shù)調(diào)用的結(jié)果,并在出現(xiàn)相同的輸入時(shí)返回它們。它可以減少冗余計(jì)算,加快程序速度。

首先是低效的版本。

# Example of inefficient code
 def fibonacci(n):
   if n == 0:
     return 0
   elif n == 1:
     return 1
   return fibonacci(n - 1) + fibonacci(n-2)
 
 def test_10_v0(list_of_numbers):
   output = []
   for i in numbers:
     output.append(fibonacci(i))
 
   return output

然后我們使用Python的內(nèi)置functools的lru_cache函數(shù)。

# Example of efficient code
 # Using Python's functools' lru_cache function
 import functools
 
 @functools.lru_cache()
 def fibonacci_v2(n):
   if n == 0:
     return 0
   elif n == 1:
     return 1
   return fibonacci_v2(n - 1) + fibonacci_v2(n-2)
 
 def _test_10_v1(numbers):
   output = []
   for i in numbers:
     output.append(fibonacci_v2(i))
 
   return output

結(jié)果如下:

# Summary Of Test Results
      Baseline: 63.664 ns per loop
      Improved: 1.104 ns per loop
 % Improvement: 98.3 %
      Speedup: 57.69x

使用Python的內(nèi)置functools的lru_cache函數(shù)使用Memoization加速57x。

lru_cache函數(shù)是如何實(shí)現(xiàn)的?

“LRU”是“Least Recently Used”的縮寫(xiě)。lru_cache是一個(gè)裝飾器,可以應(yīng)用于函數(shù)以啟用memoization。它將最近函數(shù)調(diào)用的結(jié)果存儲(chǔ)在緩存中,當(dāng)再次出現(xiàn)相同的輸入時(shí),可以提供緩存的結(jié)果,從而節(jié)省了計(jì)算時(shí)間。lru_cache函數(shù),當(dāng)作為裝飾器應(yīng)用時(shí),允許一個(gè)可選的maxsize參數(shù),maxsize參數(shù)決定了緩存的最大大小(即,它為多少個(gè)不同的輸入值存儲(chǔ)結(jié)果)。如果maxsize參數(shù)設(shè)置為None,則禁用LRU特性,緩存可以不受約束地增長(zhǎng),這會(huì)消耗很多的內(nèi)存。這是最簡(jiǎn)單的空間換時(shí)間的優(yōu)化方法。

10、向量化

import numpy as np
 
 def test_11_v0(n):
   # Baseline version
   # (Inefficient way of summing numbers in a range)
   output = 0
   for i in range(0, n):
     output = output + i
 
   return output
 
 def test_11_v1(n):
   # Improved version
   # (# Efficient way of summing numbers in a range)
   output = np.sum(np.arange(n))
   return output

向量化一般用于機(jī)器學(xué)習(xí)的數(shù)據(jù)處理庫(kù)numpy和pandas

# Summary Of Test Results
      Baseline: 32.936 ns per loop
      Improved: 1.171 ns per loop
 % Improvement: 96.4 %
      Speedup: 28.13x

11、避免創(chuàng)建中間列表

使用filterfalse可以避免創(chuàng)建中間列表。它有助于使用更少的內(nèi)存。

def test_12_v0(numbers):
   # Baseline version (Inefficient way)
   filtered_data = []
   for i in numbers:
     filtered_data.extend(list(
         filter(lambda x: x % 5 == 0,
                 range(1, i**2))))
   
   return filtered_data

使用Python的內(nèi)置itertools的filterfalse函數(shù)實(shí)現(xiàn)相同功能的改進(jìn)版本。

from itertools import filterfalse
 
 def test_12_v1(numbers):
   # Improved version
   # (using filterfalse)
   filtered_data = []
   for i in numbers:
     filtered_data.extend(list(
         filterfalse(lambda x: x % 5 != 0,
                     range(1, i**2))))
     
     return filtered_data

這個(gè)方法根據(jù)用例的不同,執(zhí)行速度可能沒(méi)有顯著提高,但通過(guò)避免創(chuàng)建中間列表可以降低內(nèi)存使用。我們這里獲得了131倍的提高

# Summary Of Test Results
      Baseline: 333167.790 ns per loop
      Improved: 2541.850 ns per loop
 % Improvement: 99.2 %
      Speedup: 131.07x

12、高效連接字符串

任何使用+操作符的字符串連接操作都會(huì)很慢,并且會(huì)消耗更多內(nèi)存。使用join代替。

def test_13_v0(l_strings):
   # Baseline version (Inefficient way)
   # (concatenation using the += operator)
   output = ""
   for a_str in l_strings:
     output += a_str
 
   return output
 
 def test_13_v1(numbers):
   # Improved version
   # (using join)
   output_list = []
   for a_str in l_strings:
     output_list.append(a_str)
 
   return "".join(output_list)

該測(cè)試需要一種簡(jiǎn)單的方法來(lái)生成一個(gè)較大的字符串列表,所以寫(xiě)了一個(gè)簡(jiǎn)單的輔助函數(shù)來(lái)生成運(yùn)行測(cè)試所需的字符串列表。

from faker import Faker
 
 def generate_fake_names(count : int=10000):
   # Helper function used to generate a 
   # large-ish list of names
   fake = Faker()
   output_list = []
   for _ in range(count):
     output_list.append(fake.name())
 
   return output_list
 
 l_strings = generate_fake_names(count=50000)

結(jié)果如下:

# Summary Of Test Results
      Baseline: 32.423 ns per loop
      Improved: 21.051 ns per loop
 % Improvement: 35.1 %
      Speedup: 1.54x

使用連接函數(shù)而不是使用+運(yùn)算符加速1.5倍。為什么連接函數(shù)更快?

使用+操作符的字符串連接操作的時(shí)間復(fù)雜度為O(n2),而使用join函數(shù)的字符串連接操作的時(shí)間復(fù)雜度為O(n)。

總結(jié)

本文介紹了一些簡(jiǎn)單的方法,將Python for循環(huán)的提升了1.3到970x。

  • 使用Python內(nèi)置的map()函數(shù)代替顯式的for循環(huán)加速970x
  • 使用set代替嵌套的for循環(huán)加速498x[技巧#3]
  • 使用itertools的filterfalse函數(shù)加速131x
  • 使用lru_cache函數(shù)使用Memoization加速57x


責(zé)任編輯:華軒 來(lái)源: DeepHub IMBA
相關(guān)推薦

2022-08-09 09:10:31

TaichiPython

2021-02-17 13:20:51

forpandas語(yǔ)言

2013-09-24 09:40:41

Java圖形加速

2019-02-16 05:00:49

物聯(lián)網(wǎng)IOT工業(yè)物聯(lián)網(wǎng)

2020-06-28 10:07:31

加速軟件項(xiàng)目IT領(lǐng)導(dǎo)軟件開(kāi)發(fā)

2021-05-31 09:00:00

數(shù)據(jù)存儲(chǔ)存儲(chǔ)系統(tǒng)工具

2019-01-25 19:00:49

Windows 10加速PC方法

2020-05-14 14:21:50

谷歌AI數(shù)據(jù)

2021-09-06 14:57:24

AI 數(shù)據(jù)人工智能

2023-04-13 09:03:43

IT領(lǐng)導(dǎo)者數(shù)字計(jì)劃

2023-03-02 13:10:40

數(shù)字化轉(zhuǎn)型

2019-03-27 13:45:44

MySQL優(yōu)化技巧數(shù)據(jù)庫(kù)

2019-10-08 10:28:36

Python程序員鏡音雙子

2023-04-03 13:48:13

云成本云計(jì)算

2021-02-01 10:26:11

數(shù)字業(yè)務(wù)IT領(lǐng)導(dǎo)者首席信息官

2023-12-29 09:23:25

Python回調(diào)函數(shù)遍歷字典

2014-03-06 09:52:23

數(shù)據(jù)備份恢復(fù)數(shù)據(jù)安全

2017-11-03 10:40:25

Python復(fù)制文件方法

2022-07-13 16:06:16

Python參數(shù)代碼

2024-11-15 07:00:00

Python發(fā)送郵件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 午夜影视大全 | av天天澡天天爽天天av | 久久在线 | 日韩综合在线 | 国产一区二区自拍 | 日韩在线小视频 | 国产做a爱片久久毛片 | 超碰97免费 | 日韩av一区二区在线观看 | 日本a视频 | 亚洲综合在线一区 | 国产精品一区二区三区在线播放 | 国产日韩欧美电影 | 亚洲一区二区三区免费在线 | 欧美成人免费在线 | 日韩欧美在线播放 | 欧美aⅴ在线观看 | 麻豆久久久久久 | 亚洲码欧美码一区二区三区 | 粉嫩国产精品一区二区在线观看 | 一区二区三区亚洲 | 国产探花在线精品一区二区 | 国产yw851.c免费观看网站 | 成人视屏在线观看 | 亚洲精品视频在线观看免费 | 涩涩视频大全 | 91在线精品一区二区 | 亚洲性在线 | 色婷婷国产精品 | jizz视频| 久久久精品天堂 | 欧美一区二区在线视频 | 午夜激情小视频 | 一呦二呦三呦国产精品 | 青久草视频| 日韩精品免费 | 日韩av看片 | 国产精品一区二区av | 91xxx在线观看 | 婷婷亚洲综合 | 日韩一区在线播放 |