话说为什么大家会集中讨论GIL?在这里题主的标准线是一个按bit处理的单线程DFS啊……几乎没有GIL发挥的余地好么……

这个八皇后的DFS,我的C++代码在不加某些评估性剪枝的情况下对15需要算18s左右(开O2大约8.6秒,与题主描述基本一致),但是可以确定的是你的解决方案里用了循环与递归。接下来需要分析的无非是Python慢在哪个细节,以及能否改进的问题。

下面是两段用来测试的代码,首先是Python的:

#!/usr/bin/env python3

import time

def calc(n, i=0, cols=0, diags=0, trans=0):

if i == n:

return 1

else:

rt = 0

for j in range(n):

col = 1 << j

diag = 1 << (i - j + n - 1)

tran = 1 << (i + j)

if (col & cols) == 0 and (diag & diags) == 0 and (tran & trans) == 0:

rt += calc(n, i+1, cols | col, diags | diag, trans | tran)

return rt

if __name__ == '__main__':

t = time.time()

print(calc(13))

print(time.time() - t)

以及C++代码:

#include

#include

using namespace std;

long calc(int n, int i = 0, long cols = 0, long diags = 0, long trans = 0) {

if (i == n) {

return 1;

} else {

long rt = 0;

for (int j = 0; j < n; j++) {

long col = (1 << j);

long diag = (1 << (i - j + n - 1));

long tran = (1 << (i + j));

if (!(col & cols) && !(diag & diags) && !(tran & trans)) {

rt += calc(n, i + 1, col | cols, diag | diags, tran | trans);

}

}

return rt;

}

}

int main() {

auto t = chrono::system_clock::now();

cout << calc(13) << endl;

cout << (chrono::system_clock::now() - t).count() * 1e-6 << endl;

return 0;

}

这里的C++代码没按照OOP去写,怎么简单怎么来吧……

测试机器配置是Core i7 4870HQ,编译器用的Clang++ 8.1.0,Python解释器则是CPython 3.6.0。没测试15的数据量只测试一下13,因为15太费时间了……

由于这里压根不涉及多线程问题,那基本上就跟GIL没有半毛钱关系了。

对于n=13,C++代码跑了0.48秒。为了确保不是编译器悄悄干了活,我特地打成了-O0(实际上开O2能到0.2秒左右)。Python跑了24秒。

对于这个例子,最直接的影响其实在于:Python是逐句解释执行的,C++是先编译成本地代码,期间还有编译期的类型检查,不存在动态类型、动态检查,并且可以进行编译器优化。

之后应该考虑一下能不能提高一点点效率呢?

然后根据一般规律,Python的循环很慢,我们可以考虑改成列表展开:

def calc(n, i=0, cols=0, diags=0, trans=0):

if i == n:

return 1

else:

return sum(

[

calc(n, i + 1, cols | (1 << j), diags | (1 << (i - j + n - 1)), trans | (1 << (i + j)))

for j in range(n)

if (cols & (1 << j)) == 0 and (diags & (1 << (i - j + n - 1))) == 0 and (trans & (1 << (i + j))) == 0

]

)

理应速度更快,实时也验证了:这样的Python代码需要跑18秒左右。仍然存在数量级的差异,并没有解决根本问题,但是说明了一点,CPython中for loop的实现其实一点都不快。

而后考虑一下,如果我们使用其它解释器,特别是包含JIT的解释器,它将在执行过程中尝试将代码编译成本地二进制编码并执行,同时还能赋予一些额外优化,会不会好很多?

那么单纯地尝试一下PyPy3(5.8.0-beta, Python 3.5.3),代码能有多快?

实际上,单纯的只是替换一下解释器,换成PyPy来做的话,原本这个24s的Python源码就只需要1s左右了。单单一个JIT可以使得性能提升一个数量级,充分说明官方的CPython解释器的性能真心很烂……

PyPy的JIT比较简单纯粹,并不是很激进,但是同样的代码如果能借助更好的JIT,以及更高性能的库,则可以体现出完全不同的性能差。例如,如果使用llvm做JIT,同时加上能使用一些成熟的数学库做优化。我们知道NumPy这样的C扩展能够很大程度提高Python做数值计算的性能,同样的我们也可以用Cython或者直接用C写Python扩展来强化计算能力。但是人都是懒的,重新写代码实在是有些麻烦。对于Python这种生态强大的玩意来说,如果你的计算代码中只是单纯的使用了numpy的简单结构以及Python自身的标准结构,使用numba可能是最简单快速的办法。

#!/usr/bin/env python3

import time

from numba import jit

@jit

def calc(n, i=0, cols=0, diags=0, trans=0):

if i == n:

return 1

else:

rt = 0

for j in range(n):

col = 1 << j

diag = 1 << (i - j + n - 1)

tran = 1 << (i + j)

if (col & cols) == 0 and (diag & diags) == 0 and (tran & trans) == 0:

rt += calc(n, i+1, cols | col, diags | diag, trans | tran)

return rt

if __name__ == '__main__':

t = time.time()

print(calc(13))

print(time.time() - t)

这里只是很简单地加入了两行代码:从numba导入jit,用jit装饰我们的计算函数。这段代码的运行时间直接就缩短到了0.4s,和C++版本的O0编译后的程序速度几乎一样。这还是考虑到JIT需要预热的情况在内。这段代码,若是计算15的规模,只需要6.5s左右,甚至优于开O2的C++版本。

究其原因,JIT不仅仅在运行过程中将代码转为本地机器码,同时还会尝试进行优化。如果用cProfile之类的玩意分析一下运行过程,可以清楚看到这个优化过程。

python比javascript快多少_为什么Python比C++慢很多?相关推荐

  1. python写算法快吗_用python写排序算法

    希尔排序 希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能.这样可以让一个元素可以一次性地朝最终位置前进一大步.然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到 ...

  2. python和javascript哪个好_JavaScript与Python:主要区别

    Python与JavaScript之间的主要区别在于它们的用法.Python有许多用途,包括数据科学和Web应用程序的后端.JavaScript主要用于Web应用程序的前端,很少在浏览器外部使用. P ...

  3. python二进制文件 删除尾部数据_在Python中读取和切片二进制数据文件的最快方法...

    我有一个处理脚本,用于提取"uint16"类型的二进制数据文件,并一次以6400块的形式进行各种处理.该代码最初是用Matlab编写的,但由于分析代码是用 Python编写的,我们 ...

  4. python做作业没头绪_使用Python做作业

    python做作业没头绪 Applying OpenCV and Tesseract to do your math-homework 应用OpenCV和Tesseract进行数学作业 The pos ...

  5. python里load什么意思_【python】json中load和loads区别

    相同点 dump 和 dumps 都实现了序列化 load 和 loads 都实现反序列化 变量从内存中变成可存储或传输的过程称之为序列化 序列化是将对象状态转化为可保存或可传输格式的过程. 变量内容 ...

  6. python语言是编译执行_加速Python运行的工具

    加速Python运行的工具应用 如果你需要让你的Python程序加速运行,在不同的层次有一些不同的解决方案: 重写 你的 Python 代码, 通过 并行化parallelizing 和 优化opti ...

  7. python 按需加载_基于python的opcode优化和模块按需加载机制研究(学习与个人思路)(原创)...

    基于python的opcode优化和模块按需加载机制研究(学习与思考) 姓名:XXX 学校信息:XXX 主用编程语言:python3.5 文档转换为PDF有些图片无法完全显示,请移步我的博客查看 完成 ...

  8. python字符串大写字母个数_【python实例】统计字符串里大写字母,小写字母的个数和非字母的个数...

    """ 给定一个以下字符串:统计大写字母的个数,小写字母的个数,非字母的个数. str1 = "ajdkkKDKEK1343KFKiriromfkfKKRIOW ...

  9. python开发效率高吗_提升python开发者工作效率的六个库,你知道几个?

    无论你现在是否从事Python开发,以后想从事Python,你最好了解一下几个库,它能让你无论是学习,还是职业进阶都有很大帮助. Python 凭借其易用的特点,已经被工业界和学术界广泛采用.另一方面 ...

最新文章

  1. Java多线程学习(二)---线程创建方式
  2. API接口通讯参数规范
  3. 接软件开发项目,你需要知道这些!
  4. 为view设置虚线边框
  5. ucos-II之就绪表解读
  6. 【排序算法】选择排序
  7. linux sdr 2832u软件无线电,使用R820T+RTL2832U玩软件无线电
  8. html注册cab包,OCX控件打包成CAB并实现数字签名过程
  9. 向量点乘(即内积)和叉乘(即外积、向量积)区别与意义分析
  10. Python 自动化办公之自动识别并点击按钮
  11. 软件架构风格介绍和总结
  12. 第三方自动投票软件制作教程
  13. Therefore, hence, so, then, thus
  14. python 算法测试结果自动保存到excel表格
  15. vue项目中 一行文本 文字 根据关键字 改变颜色 改变展示颜色2
  16. 微信怎么制作小程序?制作微信小程序流程
  17. 改变无数人命运的上证指数
  18. win10 下Android 连接电脑本地MySQL数据库
  19. 《教学综合管理系统》研究日志
  20. Halcon焊点检测例子解析

热门文章

  1. JAVA 创建学生类
  2. Maven将jar包install到本地仓库deploy到远程仓库命令
  3. python代码实现文件复制txt文件_工具类(1.1)
  4. 线程的生命周期 和 线程的通讯
  5. mysql5.7.14_mysql 5.7.14 下载安装配置方法图文教程
  6. linux java setting,setting java_home and path environmental variables in linux [duplicate]
  7. Python刷题-7
  8. 正则表达式(面试会考)
  9. java uuid fasterxml_可笑!可悲!可叹!你竟然还不知道Java如何生成UUID?
  10. Android助手 V23.34,Android助手