丰田产业技术纪念馆之二

今年开始准备好好整理这些旅行的感想和照片,以及知识。对于日本这个国家,大概从戚继光时代开始,甲午海战、抗日战争种种,使我们的感觉比较复杂。日本的井井有条、一丝不苟给我们留下了太深刻的印象,说实话山山水水方面比起泱泱中华是差的太远了,很多时候的好感因为服务,因为干净。明治维新 1868年开始,这个曾经连文字都没有的国家逐渐成为了世界强国,总是有一些值得学习的地方。

丰田产业技术纪念馆在日本不算小,名古屋也因为丰田更加充实。友人说郊区还有一个专门的丰田汽车馆,下次有机会再去看看。

这个冬天 流浪地球

流浪地球,这个电影这不错,没想到中国的科幻片已经可以达到这样的高度。我才不介意网上那些刷存在感的人,一定要说这部电影这里不好,那里不好。电影么,就是好看就行,想那么多累么。

刘慈欣本来作品就不错,制作团队那么认真,演员也还行,道路千万条的梗也很好笑,很佩服这些电影人,为了梦想而执着,成功的背后是为人不知的艰辛和付出。

这个春节,有流浪地球,让我们耳目一新。让我为了坚持梦想多一个榜样和理由!

丰田产业技术纪念馆之一

因为第一辆车是丰田的,加上对于丰田的精益管理始终有朝圣之心,所以这次去了距离住地较近的丰田产业技术纪念馆。果然很震撼。

之前也是孤陋寡闻了,原来丰田是从纺织机械起家的,从二十世纪初就开始了,经历百多年了,一直到全球汽车制造的翘楚,值得学习。纪念馆里也是无所不用其极,除了常规想得到的以外,竟然还有日本最擅长的动漫,让我们仿佛回到了丰田的创业时代。

2019.2 名古屋之游

2018年的元旦,在名古屋,2019年的春节,又去了名古屋,这次去了丰田产业技术馆和铁道博物馆,感触颇深。然后去了鸟羽,位于伊势弯的一隅,鸟羽水族馆挺不错,日本养殖数量第一的水族馆,以及鸟羽美丽的风景。

感觉还是有些国人对于日本这个国家有着一些误解,如同颜真卿书法事件,我的想法是,学习人家好的地方,而绝大多数事情和政治无关。

今年准备好好用考据的方式将去过的地方记录下来,应该会是一种有趣的经历。

今天,情人节

休假回来,昨天上了一天班,感觉大家还是沉浸在过年的气氛中,挺好的。事情不多,会议不多。估计工作的节奏正式开始要下周一了。

今天,情人节,这个节日记得是学生时代和圣诞节一起开始迅速流行,或许我们的传统节日有点隆重,而这两个节日其实对我们来说没有什么高不可攀的意义,就是热闹,各种气氛。

形式不论,心中有爱。

2019 新春快乐

好像说今年是春晚 36 年了,小时候对 cctv 有个节目还是印象深刻的,叫做九州方圆,当时不懂为什么叫这个名字,后来才知道“九州”就是说中国。

从昨天小年夜起,微信就开始很热闹了,家人、同事、朋友,各类群,响个不停。从今天早上开始,更是各种祝福拜年此起彼伏。好像已经几乎没有人用短信、电话拜年了(也或许我孤陋寡闻)。

支付宝自然不甘人后,抢五福的活动大家玩的不亦乐乎,从去年开始我也投入其中,今年更是复杂,又是 AR 扫,又是浇水答题,终于在昨天搞定了最难找的敬业福。等着晚上开奖,可以中个几毛钱。。。

过年的方式在变,年味或许也不如过去那样浓烈,但是心中还是有一份感激,新春快乐!猪事顺利!

2019 春节将至

今年春节不早不晚,2018年跌宕起伏,圆了一些梦想,也是很多煎熬。

互联网金融的热潮终于过去,经历了最风光的大约 2015 2016 2017 三年,P2P 整个行业几乎一蹶不起。还好,公司始终居安思危,使得我们依然在支付、金融、科技等方面前行,而上市实在不容易,拉开了和竞争对手的差距。只是,前路依然不容易。诚惶诚恐者生存。

明天是春节前最后一个上班日,今天还是有一般的同事在,有些组到今天还有不少项目在开发,很辛苦。

2018年下半年开始,所谓互联网寒冬,而我真的觉得其实无所谓寒冬,或者任何时候都要做好过冬的准备。

新春快乐!大家快乐!

计算缓存、优化算法和加速 Python 执行 第三部分

用列表计算进行优化

Python 性能的确一般,但是 Python 的常规函数的性能还是不错的, Python 解释器是用 C 语言实现的,在基本操作层面,已经优化了很多年,所以虽然有 requests 这样石破天惊的扩展包来取代 Python 内部的函数包,但是基本上没有人会去自己实现 Python 的列表计算等最常规的功能。在我们实践中的大部分场景,包括以 server 服务为主的场景,Python 的性能、稳定性都非常在线,也没有 Java 的 JVM 带来的很多不可控制的问题。我们用程序是去解决更多的业务逻辑,所以易学、易维护这些特性也是要关注的。

我们来看看用列表操作实现斐波那契数列的版本:

def list_fib(n):

    list_f = []
    f = 1
    list_f.append(f)
    list_f.append(f)  
    for i in range(n-2):
        f = list_f[-1] + list_f[-2]  
        list_f.append(f)
    return f


if __name__ == "__main__":
    x = 47
    start = time.time()
    res = list_fib(x)
    elapsed = time.time() - start
    print("Python Computed fib(%s)=%s in %0.8f seconds" % (x, res, elapsed))

执行结果就是秒开:

Python Computed fib(47)=2971215073 in 0.00002408 seconds

基本是所有执行方法中最快的之一,因为执行几十次的列表运算对于 Python 来说实在很轻松。

Python 的列表运算我们在《Python 机器学习》一书中有专门章节讨论过,列表是 Python 中非常重要的数据类型,不能小看,像这样一个数学运算的场景,用列表也可以简单而高效的完成。

谈谈 PyPy

CPython,也就是我们平时使用的 Python 解释器,因为这个解释器是用 C 写的,所以我们称之为 CPython,它并不是 Python 的唯一发行版,比如还有 PyPy http://pypy.org ,它通过即时编译器(JIT)来加快代码执行速度。在之前斐波那契数列的计算例子中有过比较,要比使用 CPython 快 5 倍左右。PyPy 完全支持 Python 标准库,但它不是支持所有的第三方扩。其平均可以提升 2-5 倍性能,并且你的应用所使用的扩展包都兼容,那么 PyPy 是可以尝试一下的。

维基百科中文版 https://zh.wikipedia.org/wiki/PyPy 关于 PyPy 的资料比较老,可以参考英文版 https://en.wikipedia.org/wiki/PyPy

PyPy 是 Armin Rigo 开发的,一己之力,能做这么多,真的很厉害!

PyPy 的前端是个严格的 Python 子集,称之为 RPython,这里的 R 是严格(Restricted)的意思。RPython 对 Python 语言做了一些约束,以便在之后编译时可以推断出变量类型等诸多优化的前提。PyPy 项目开发了一个工具链,用于分析 RPython 代码并将其转换为字节代码形式,最后用 C 语言来编译,达到将大部分代码编译成机器代码以提高执行速度的目的。它有设计精良的垃圾收集器和内存管理。最后,它包含了 JIT 引擎,在解释器层面上构造“即时的优化代码”。

概念很多,我们一一道来。

什么是 RPython

RPython 有自己的文档站点:https://rpython.readthedocs.io/en/latest/

你写的 Python 程序首先会经过一个 PyPy 的解释器来生成 RPython 代码,前面说了,生成的 RPython 代码比较严格,这样后面的编译工作就好开展,真正的 CPython 是用 C 写的解释器,但是并没有将你的 Python 代码编译成机器码,所以 Python 一般情况下会被诟病执行速度慢。

所以说 PyPy 实际上是包含两个组件:

  1. Python 解释器,输入是常规的 Python 程序,输出 RPython 代码,且这个 Python 解释器本身使用 RPython 写的。
  2. RPython 编译工具链,包括将 Python 代码转换成字节码和 C 代码,编译成本地二进制代码的一系列工具和步骤。

所以大家理解为什么说 PyPy 对 Python 兼容性很好,但是安装一些复杂的本身通过 C 优化过的扩展包兼容性又不太好的原因了。

RPython 编译过程

在官方文档中,PyPy 的整个工作不叫“编译”,而是叫“翻译”(translate)。RPython 编译器是一组工具链,将 RPython 程序编译到目标语言,比如 C。这个编译器本身是用 Python 写的。流程如下:

编译器读入转换到 RPython 样式的代码。RPython 会对普通的、带有一些动态性能的 Python 代码做一些限制,比如函数不能动态被生成、变量不能够不确定到底存储什么类型等,一些在解释执行时候没有问题的细节,在这里都会被严格对待。

编译器通过一个称之为抽象解释器(abstract interpretation)的工具构建 RPython程序的流程图。这个抽象解释器使用 PyPy 的 Python 解释器来解析 RPython 程序,这里开始的流程非常复杂,涉及到很多编译相关的技术细节,在 RPython 官方文档这里有一个更加详细的流程图:

笔者才疏学浅,就不再逐一展开了,有兴趣的朋友可以参考这些资料:

https://rpython.readthedocs.io/en/latest/translation.html

https://www.aosabook.org/en/pypy.html

有更加完整的说明和解释。

编译器一步步通过生成的流程图,最后生成基于 C 语言的代码,当然,在生成 C 代码的时候还要加入很多异常处理、内存管理等。通过下面这一连串的动作,终于可以将 Python 代码转换到 C 代码了。

什么是 JIT

什么是即时编译 JIT,Wiki 的定义(https://zh.wikipedia.org/wiki/即时编译) 很清晰:即时编译是动态编译的一种形式,是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态解释。静态编译的程序在执行前全部被翻译为机器码,而动态解释执行则是一句一句边运行边翻译。

即时编译器则混合了这二者,一句一句编译源代码,但是会将编译过的代码缓存起来以提高性能。相对于静态编译代码,即时编译的代码可以处理延迟绑定并增强安全性。

即时编译器有两种类型,一是字节码翻译,二是动态编译翻译。微软的.NET Framework,还有绝大多数的 Java 实现,都依赖即时编译以提供高速的代码执行。Ruby 的第三方实现 Rubinius 和 Python 的第三方实现 PyPy 也都通过 JIT 来明显改善了解释器的性能。

PyPy 的 JIT 机制比较与众不同的地方在于,别的编译器直接执行程序代码,其编译器中支持 JIT 特性,而 PyPy 则是在将 Python 代码转换为 RPython 代码的时候加入的,然后将其编译成可执行代码后就自带 JIT 了。这样的方式也算是比较巧妙的设计了,我理解,PyPy 对性能提升很大程度就在这里了。只是,通过这么复杂的两次转换,Python 代码的性能虽然有了几倍的提升,但和 Java、C 等还是有不小的差距。而随着硬件服务器资源的摩尔定律,引入 PyPy 本身增加的项目复杂度以及其对于第三方扩展包的支持问题,似乎还是使用 Python 标准的 CPython 解释器比较好,综合使用成本低很多。PyPy 解决问题的思路非常不错,但还是有很长的路要走。