Python性能优化的一些思路

Python是解释性语言,性能相对较低。但是通过一些性能优化方法,可以将性能提升百倍以上。以下是本人在Python编程中采用过的一些性能优化思路,分享给大家参考。

1、采用多进程处理
Python由于GIL的限制,多线程只能利用1个CPU,难以用于性能提升。但是,可以把工作划分为独立的任务,采用多进程模式来处理,如此可以充分发挥多核CPU的算力;下面是一个从网上找到的一个多进程池的示例代码,供参考

# -*- coding:utf-8 -*-
# 求最大公约数
import random
import progressbar

max_workers = 8
def gcd(pair):
    a, b = pair
    low = min(a, b)
    for i in range(low, 0, -1):
        if a % i == 0 and b % i == 0:
            return i

#numbers = [
#    (1963309, 2265973), (1879675, 2493670), (2030677, 3814172),
#    (1551645, 2229620), (1988912, 4736670), (2198964, 7876293)
#]

def main():
    #with concurrent.futures.ProcessPoolExecutor() as executor:
    #    for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
    #        print('%d is prime: %s' % (number, prime))
    numbers = [(random.randint(1000000, 10000000), random.randint(1000000, 10000000)) for i in range(0, 200)]
    print("numbers len:", len(numbers))
    # print("numbers:", numbers)

    import time
    from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, Executor

    start = time.time()
    split_len = 5 * max_workers
    numbers_split = [numbers[i:i + split_len] for i in range(0, len(numbers), split_len)]
    with progressbar.ProgressBar(max_value=len(numbers_split)) as bar:
        counter = 0
        results = []
        for number in numbers_split:
            bar.update(counter)

            with ProcessPoolExecutor(max_workers=max_workers) as pool:
                results.append(list(pool.map(gcd, number)))

            counter += 1
            print("counter:", counter)

    end = time.time()
    print('ProcessPoolExecutor Took %.3f seconds.' % (end - start))
    print('result:', results)

if __name__ == '__main__':
    main()

2、pandas的DataFrame改用numpy数组来处理
我们经常需要使用pandas来处理数据。pandas处理二维数据非常方便。但是,pandas的处理速度比numpy慢很多。如果pandas的处理成为性能瓶颈时,可以改用numpy来处理,或者pandas与numpy结合一起使用。以下代码可以非常容易的把pandas的二维数据转为numpy的二维数组。转为numpy二维数组后,操作各列,需要使用数字来索引,没有pandas的列名,稍稍不便,但是性能可以提升2到4倍。

# -*- coding: utf-8 -*-
import numpy as np 
import pandas as pd

#data = pd.DataFrame(np.arange(20).reshape(4,5),index = list("ABCD"),columns=list('vwxyz'))
data = pd.DataFrame(np.arange(100).reshape(20,5),columns=list('vwxyz'))
data_arr = data.values
print(data)
print(data_arr)

3、使用numpy的排序等函数时,把object类型转换为实际的类型
从numpy的二维数组中按行切片,再按列切片时,如果各列的数据类型不一致,切片后float64等数字型数据的数据类型可能变为object类型。这时,依然可以进行排序、加减等运算,不会出错。但是,性能会低很多。如果切片后,使用astype函数,先转换成float64等实际的数据类型,排序性能可以提升2到3倍。

4、性能瓶颈改用C++函数实现
Python是胶水语言,可以调用C++实现的函数。C++实现的函数经过编译,性能可以提升30倍到100倍。编译C++函数供Python调用,有多个方法。我们习惯依赖Boost.Python这个库来编译C++函数供Python调用。我们的一个统计分析瓶颈,采用Python来实现时,需要运算1个小时。把瓶颈部分代码改用C++实现,在Python中调用后,统计分析只需要2分钟左右,极大提高了分析效率。如何使用Boost.Python编译C++函数导出给Python使用,网上很多例子,请自行百度一下即可。

5、根据数据特点,改用不同的思路来处理数据
我们处理数据时,排序通常采用快速排序算法。快速排序算法的时间复杂度为O(N*logN)。一般情况下,快速排序是平均性能最好的排序算法了。但是,随着数据量的增长,快速排序算法的时间会线性增加。这时候,需要根据自己的数据特点,采用其它一些方式来自行实现排序,性能可能会获得很大提升,避免排序时间随着数据量增大线性增长。我们工作中的一个数据处理,数据量增长后,采用快速排序时需要21小时。采用我们自行编写的排序算法,结合快速排序,把处理时间缩短到了20多分钟,极大提高了处理效率。

你可能感兴趣的:(python,python,算法,数据分析)