一行代码让python的运行速度提高100倍

我们先看一个原始代码:

import time

def foo(x, y):
    tt = time.time()
    s = 0
    for i in range(x, y):
        s *= i
    print('time:{}'.format(time.time() - tt))
    return s

print(foo(1,100000000))

看一下运算时间结果:

time:8.983859300613403

然后我们加一行代码,再看看结果:

import numba as nu
import time
@nu.jit()
def foo(x, y):
    tt = time.time()
    s = 0
    for i in range(x, y):
        s *= i
    print('time:{}'.format(time.time() - tt))
    return s

print(foo(1,100000000))

看一下运算时间结果:

time:0.16590428352355957

咦~好像快了不止100倍啊

我丢,厉害了我的一行代码

下面来讲解一下神奇的 numba

如何使用numba
import numba as nb
只用1行代码即可加速,对loop有奇效

这回肯定又有人问了神马是loop,这里我讲解一下: loop就是循环的意思
然后numba 的优势就是 loop,对循环(loop)有奇效,而往往在科学计算中限制python速度的就是loop。

但要注意的是,numba对没有循环或者只有非常小循环的函数加速效果并不明显,用不用都一样。(偷偷告诉你,numba的loop甚至常常比numpy的矩阵运算还要快)

重点:
numba可以把各种具有很大loop的函数加到很快的速度,但numpy的加速只适用于numpy自带的函数。
示例:

import numba as nb
import numpy as np
import time
# 用numba加速的求和函数
@nb.jit()
def nb_foo(x, y):
    tt = time.time()
    s = 0
    for i in range(x, y):
        s += i
    print('time:{}'.format(time.time() - tt))
    return s

print(nb_foo(1,100000000))
# 没用numba加速的求和函数
def py_foo(x, y):
    tt = time.time()
    s = 0
    for i in range(x, y):
        s += i
    print('time:{}'.format(time.time() - tt))
    return s

print(py_foo(1,100000000))

a = list(range(100000000)) # 创建一个长度为100000000的数组

start = time.time()
np.sum(a) # numpy自带的求和函数
end = time.time()
print(end-start)

start = time.time()
sum(a) # python自带的求和函数
end = time.time()
print(end-start)

看一下输出结果:

time:0.06898283958435059	# numba加速的求和函数
4999999950000000
time:10.004251480102539		# 没加速的求和函数
4999999950000000
9.993287086486816		#numpy自带的求和函数
4.011701583862305		# python自带的求和函数

可以看出,numba甚至比号称最接近C语言速度运行的numpy还要快6倍以上。
在这里我还想说numba另一个强大的功能,矢量(vectorize)。像上面的jit一样,只要添加一行vectorize就可以让普通函数变成ufunc

from math import sin

@nb.vectorize()
def nb_vec_sin(a):
    return sin(a)

用vectorize改写的三角函数具有了和np.sin()一样的同时处理数组每个元素的功能,而且表现也不必numpy差。当遇到numpy没有的数学函数时(比如sech),用numba矢量化不失为一个好的选择。除了math中的sin,它支持的其他函数列表可以在documentation中找到(链接见附录)。

其实numpy也有矢量化的功能,只不过比numba差远了。

更多numba的加速选项

除了上面提到的jit和vectorize,其实numba还支持很多加速类型。常见的比如

​ @nb.jit(nopython=True,fastmath=True) 牺牲一丢丢数学精度来提高速度
​ @nb.jit(nopython=True,parallel=True) 自动进行并行计算

还有一个:
如果希望JIT能针对所有类型的参数进行运算,可以使用autojit:

import numba as nb
import time

@nb.autojit()
def nb_sum(a):
    start = time.time()
    Sum = 0
    for i in range(len(a)):
        Sum += a[i]
    end = time.time()
    return end-start

autoit虽然可以根据参数类型动态地产生机器码函数,但是由于它需要每次检查参数类型,因此计算速度也有所降低。numba的用法很简单,基本上就是用jit和autojit这两个修饰器,和一些类型对象。下面的程序列出numba所支持的所有类型:

print [obj for obj in nb.__dict__.values() if isinstance(obj, nb.minivect.minitypes.Type)]
[size_t, Py_uintptr_t, uint16, complex128, float, complex256, void, int , long double,
unsigned PY_LONG_LONG, uint32, complex256, complex64, object_, npy_intp, const char *,
double, unsigned short, float, object_, float, uint64, uint32, uint8, complex128, uint16,
int, int , uint8, complex64, int8, uint64, double, long double, int32, double, long double,
char, long, unsigned char, PY_LONG_LONG, int64, int16, unsigned long, int8, int16, int32,
unsigned int, short, int64, Py_ssize_t]
Numba的精度问题

精度方面,在上面我也谈到numba会自动转换数据类型以适应计算。但是在个别时候,这种自动转变类型可能会引起一些计算误差。通常这个误差是非常小的,几乎不会造成任何影响。但如果你所处理的问题会积累误差,比如求解非线性方程,那么在非常多的计算之后误差可能就是肉眼可见了。如果你发现有这样的问题,记得在jit中指定输入输出的数据类型
numba具有C所有的数据类型,比如对上面的求和函数,只需要把@nb.jit()改为@nb.jit(nb.int64(nb.int32[:]))即可。nb.int64是说输出的数字为int64类型,nb.int32是说输入的数据类型为int32,而[:]是说输入的是数组。


参考文章:
https://zhuanlan.zhihu.com/p/60994299
https://blog.csdn.net/qq_39241986/article/details/102486661

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个简单的 Python 俄罗斯方块代码: ```python import pygame import random # 初始化 Pygame pygame.init() # 定义颜色 BLACK = (, , ) WHITE = (255, 255, 255) GRAY = (128, 128, 128) RED = (255, , ) GREEN = (, 255, ) BLUE = (, , 255) YELLOW = (255, 255, ) # 定义方块大小 BLOCK_SIZE = 20 # 定义游戏区域大小 SCREEN_WIDTH = 10 * BLOCK_SIZE SCREEN_HEIGHT = 20 * BLOCK_SIZE # 定义方块形状 SHAPES = [ [[1, 1, 1], [, 1, ]], [[, 2, 2], [2, 2, ]], [[3, 3, ], [, 3, 3]], [[4, , ], [4, 4, 4]], [[, , 5], [5, 5, 5]], [[6, 6], [6, 6]] ] # 定义方块颜色 COLORS = [ WHITE, BLUE, YELLOW, GREEN, RED, GRAY ] # 定义方块类 class Block: def __init__(self, shape, color): self.shape = shape self.color = color self.x = SCREEN_WIDTH // 2 - len(shape[]) // 2 self.y = def rotate(self): self.shape = list(zip(*self.shape[::-1])) def move_left(self): self.x -= 1 def move_right(self): self.x += 1 def move_down(self): self.y += 1 def draw(self, surface): for i in range(len(self.shape)): for j in range(len(self.shape[i])): if self.shape[i][j] != : pygame.draw.rect(surface, self.color, (self.x * BLOCK_SIZE + j * BLOCK_SIZE, self.y * BLOCK_SIZE + i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)) # 定义游戏类 class Game: def __init__(self): self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("俄罗斯方块") self.clock = pygame.time.Clock() self.score = self.level = 1 self.block = Block(random.choice(SHAPES), random.choice(COLORS)) self.grid = [[] * (SCREEN_WIDTH // BLOCK_SIZE) for _ in range(SCREEN_HEIGHT // BLOCK_SIZE)] def run(self): while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: self.block.move_left() if self.check_collision(): self.block.move_right() elif event.key == pygame.K_RIGHT: self.block.move_right() if self.check_collision(): self.block.move_left() elif event.key == pygame.K_DOWN: self.block.move_down() if self.check_collision(): self.block.move_up() elif event.key == pygame.K_UP: self.block.rotate() if self.check_collision(): self.block.rotate() # 更新方块位置 self.block.move_down() if self.check_collision(): self.block.move_up() self.add_to_grid() self.check_lines() self.block = Block(random.choice(SHAPES), random.choice(COLORS)) if self.check_game_over(): self.game_over() # 绘制游戏界面 self.screen.fill(BLACK) self.draw_grid() self.block.draw(self.screen) pygame.display.update() # 控制游戏速度 self.clock.tick(10 * self.level) # 检查方块是否与边界或已有方块重叠 def check_collision(self): for i in range(len(self.block.shape)): for j in range(len(self.block.shape[i])): if self.block.shape[i][j] != : x = self.block.x + j y = self.block.y + i if x < or x >= SCREEN_WIDTH // BLOCK_SIZE or y >= SCREEN_HEIGHT // BLOCK_SIZE or self.grid[y][x] != : return True return False # 将方块加入游戏区域 def add_to_grid(self): for i in range(len(self.block.shape)): for j in range(len(self.block.shape[i])): if self.block.shape[i][j] != : x = self.block.x + j y = self.block.y + i self.grid[y][x] = self.block.color # 检查是否有完整的一行 def check_lines(self): lines = for i in range(len(self.grid)): if all(self.grid[i]): lines += 1 del self.grid[i] self.grid.insert(, [] * (SCREEN_WIDTH // BLOCK_SIZE)) self.score += lines ** 2 self.level = self.score // 100 + 1 # 检查游戏是否结束 def check_game_over(self): for i in range(len(self.grid[])): if self.grid[][i] != : return True return False # 绘制游戏区域 def draw_grid(self): for i in range(len(self.grid)): for j in range(len(self.grid[i])): pygame.draw.rect(self.screen, self.grid[i][j], (j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) # 游戏结束 def game_over(self): font = pygame.font.SysFont(None, 48) text = font.render("GAME OVER", True, RED) self.screen.blit(text, (SCREEN_WIDTH // 2 - text.get_width() // 2, SCREEN_HEIGHT // 2 - text.get_height() // 2)) pygame.display.update() pygame.time.delay(200) pygame.quit() quit() # 运行游戏 if __name__ == "__main__": game = Game() game.run() ``` 希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全 洛

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值