Pyodide:将Python科学计算全栈搬到浏览器

现在越来越多的软件都Web化,浏览器化。虽然科学计算是一计算密集型的方向,对性能要求和实时性较高。但是数据计算方面也一直在做着这样的探索和发展。

Jypyer notbook项目让科学计算真正实现了Web化,而JS语言的发展和WebAssembly技术的兴起,让科学计算的浏览器化,在客户端实现数据计算处理和可视化变成了可能。今天虫虫要给大家介绍就是一款来自Mozilla的实验项目Pyodide,一款用于在浏览器中运行完整Python科学计算处理工具栈环境的软件。

概述

Pyodide项目源于Mozilla的项目Iodide。Iodide是基于Web技术的数据科学实验和通信工具。它旨在在浏览器中进行数据计算。问题是通用的浏览器语言JS,没有成熟的数据科学处理库,也缺乏一些数值计算很有用功能和数据结构,比如运算符重载等。虽然完善JS语言本身是一条路,但是这条路太慢,所以有必要投机取巧的走一条捷径出来。这就是Pyodide项目的所做的事情:通过将成熟活跃的Python科学计算工具栈引入浏览器来满足数据科学计算的需要。Pyodide提供了一个完整的标准Python解释器,它完全在浏览器中运行,可以完全访问浏览器的Web API。下面以一个快速实例开始:

代码显示效果如下:

了解更多关于Pyodide可以做的事情的最好方法就是去尝试吧!有一个演示笔记本(50MB下载),介绍了高级功能。本文的其余部分将更深入地探讨其工作原理。

技术架构

类似项目分析

Pydodie设计时候参考了很多现有项目,在实现Python到浏览器这"最后一公里"问题上,市面上已经有很多的项目,但是目前还没有一个项目可以做到Python科学计算栈的转化,该栈包括不限于Python类库:NumPy,Pandas,Scipy以及Matplotlib。

Transcrypt项目可以实现Python到JS的转换。由于转换步骤本身发生在Python中,所以你需要提前完成所有的转换,或通过与服务器通信来完成这项工作。这并不能实现用户在浏览器中编写Python并实现即写急用的目标。

Brython和Skulpt项目实现了将标准Python解释器重写为JS,可以直接在浏览器中运行Python代码。但是它们都是对Python的全新实现,并且通过JS中引导,所以他们无法兼容C编写的Python扩展,比如NumPy和Pandas。因此,无法引入数据科学工具。

PyPyJs项目是使用emscripten和JS对PyPy的浏览器实现。就像PyPy一样它可以快速地运行Python代码。同样它也有于PyPy同样的C扩展性能问题。

上面这很多项目都无法解决Python科学计算的问题,这促成了Pydodie的出现:构建一个尽可能基于Python的标准并能兼容实现大多数数据科学家已经使用的Python科学堆栈的工具库的软件。

Pydodie项目技术架构的关键技术就是新兴的emscripten和WebAssembly。使用他们实现将C语言编写的现有代码库移植到浏览器运行。Pyodide使用Python化的emscripten类库cpython-emscripten为基础。

Emscripten和WebAssembly

关于emscripten互联网上有大量的介绍,在此不在赘述,在Pyodide项目中它的作用是:

实现从C/C++到WebAssembly的编译器。

实现兼容性层,使浏览器变为一个本机计算环境。

WebAssembly是一种在现代Web浏览器中运行的新语言,是对JS脚本的补充。它以接近本机的性能运行在浏览器上,旨在作为C和C++等低级语言的编译目标。

关于WebAssembly虫虫之前的文章中有介绍过,关注过虫虫的朋友可以在历史文章中浏览学习。

我们知道,实现主流的Python解释器是CPython是用C语言实现的,所以使用emscripten可以将其编译为WebAssembly。

Pyodide组成和实现步骤

Pyodide主要架构组成如下:

将主流Python解释器(CPython)的源代码和科学计算包(NumPy等)将其打包在一起,使用emscripten的编译器将它们编译为WebAssembly。

但是如果只是在浏览器总执行这个WebAssembly还不够,比如,无法在Web浏览器中执行文件操作(加载和保存文件)。为此Pyodide还引入了用JavaScript编写的虚拟文件系统。这些虚拟的文件驻留在浏览器选项卡性内存中。

通过模拟文件系统和标准科学计算环境的其他功能,将实现通过极少的改动将整个Python科学计算环境挪到Web浏览器。整个实现步骤如下:

1、已编译的Python解释器为WebAssembly。

2、通过emscripten提供的一系列的JS,用来提供系统仿真。

3、打包文件系统,包含Python解释器所需的所有文件,包括Python标准库。

这些文件可能非常大,比如Python本身为21MB,NumPy为7MB,等等依。好在这些软件包只需要下载一次,然后将它们存储在浏览器的缓存中。

局限性

通过运行CPython的单元测试对Pyodide做持续测试的,以便了解其通用性。目前还有功能是无法用的,比如Python线程。

由于浏览器的安全沙箱限制,一些他功能(比如如低级网络Socket)也不能正正常工作。

性能问题

在JS虚拟机中运行Python解释器会有性能损失,但是影响非常小,通过官方基准测试中表明:在Firefox上的比本机慢1x-12x,Chrome上慢1x-16x。还有就是,在Python中运行大量内部循环的代码往往比依赖于NumPy执行其内部循环的代码更慢。下面是在Firefox和Chrome对比同硬件本机中运行各种纯Python和Numpy基准测试的结果。

测试数据和方法键github仓库(iodide-project/)

Python和JS的交互

如果Pyodide只能做到运行Python代码并写入标准输出,虽然不错,但是没有实用价值。最重要是实现与浏览器API以及其他JS库的交互。

类型转换

Pyodide隐式地对Python和JS类型的转换,下图展示了两种语言类型转换的细节:

Python中dicts和对象实例是两种不同的类型。dicts只是健值的映射。而对象通常具对象属性和方法(methond)。在JS中没有dicts对应的数据结果,通用Object的类型来表示。Ptdodide在两者转化的时候需要用到代理和鸭子类型

代理

代理是另一种语言中变量的包装器。代理不是简单地在JS中读取变量并根据Python结构重写它,代理保持原始JS变量并"按需"调用其方法。所以任何JS变量,都可以从Python完全访问。

鸭子类型

鸭子类型是一个原则,而不是实际去问变量"你是鸭子吗?", "你像鸭子一样走路吗?"和"你像鸭子一样嘎嘎叫吗?",然后推断它是否是一只鸭子。通过鸭子类型Pyodide可以不用马上考虑推如何转换JS对象,而将其打包到代理中,让使用它的代码决定如何处理它。

当然,这种方法并能一直有效这,鸭子实际上有可能是一只兔子。Pyodide也提供了明确转换处理方法。

Pyodide使用这种高度交互,深度集成,潜在转换的方法把Python和JS融为一体。用户通过Python进行数据处理,然后用JS实现其可视化。

访问Web API和DOM

代理也是访问Web API的关键。例如,Web API的很大部分位于文档对象上。你可以通过以下方式从Python中获得:

from js import document

这会将 JS中的document对象作为代理引入到Python。然后在Python中调用它的方法:

document.getElementById("myElement")

这些都通过代理来查找document对象可以即时执行的操作。Pyodide不需要包include所有的Web API的完整列表。

多维数组

有一些类型是数据计算必须要的数据类型,比如矩阵计算中用到的多维数组,Pyodide也特别支持这些数据。多维数组是值的集合,这些值都是同一类型,但是数量巨大。Pyodide的多维数组对比Python的列表或JS数组在性能上具有很大优势。

Python中,NumPy数组是多维数组的最常用的实现。JS中是TypedArrays,它只包含一个数字类型。但是这两种类型都是一维的,多维数组需要在顶层来构建。

由于现实中这些数组可能会变得非常大,在语言运行时之间复制会非常消耗资源,而且是个非常耗时的操作。

Pyodide中利用多维数组可以无需复制就能在Python和JS之间共享数据。多维数组通常使用少量元数据来实现,这些元数据描述了值的类型,数组的形状和内存布局。数据本身通过指向内存中另一个位置的指针在元数据中索引。这个内存地址位于WebAssembly堆区的,可以在JS和Python中访问。通过在两种语言中复制元数据,来达到共享其指针指向的WebAssembly堆数据。

实时交互式可视化

在客户端浏览器中进行科学数据计算的优点之一是,交互式可视化不必通过网络进行通信以重新处理和重新显示其数据。这大大减少了交互的延迟。

完成实时交互可视的工作需要各部分的组件协同工作。下面是一个官方交互式示例动态图,它展示了使用matplotlib进行对数正态分布。

首先,使用Numpy在Python中生成随机数据。

其次,在Matplotlib获取该数据,并使用其内置的软件渲染器绘制它。

最后通过Pyodide零拷贝数组共享将像素发送回JS端,在HTML画布中呈现出来在浏览器中将这些像素显示出来。

用于支持交互性的鼠标和键盘事件由从Web浏览器调用Python的回调函数处理。

打包

Python科学计算工具栈由很多分散的软件包构成,这些包协同工作创建一个高效的计算环境。工具栈中最受欢迎的是NumPy(数值数组和基本计算),Scipy(更复杂的通用计算,如线性代数),Matplotlib(可视化)和Pandas(用于表格数据或数据帧处理)。目前Pyodide官方仓库中包含的包见下图,更多的包还在不断完善和添加中:

有些包很容易引入进来。通常,使用纯Python编写而没有其它编译语言扩展的包都非常容易。像Matplotlib这样的项目需要使用特殊代码在HTML画布中显示绘图包为中等难度。而诸如Scipy这样的包的引入则比较困难。

官方内置的包有限,用户可以根据需要自引入所需的个性化包,比如:

import numpy as np

上面语法中,Pyodide会引入NumPy库及其所有依赖项,并将其加载到浏览器中。而且包引入浏览器后会被缓存起来,下次加载时不需要重复下载。

给Pyodide打包添加新软件包,目前还不支持动态引入。需要手动添加。据悉未来版本Pyodide将会增加对PyPI的支持。

多语言支持

Pyodide目前已经得到很多语言社区的的关注,目前已经有Julia,R,OCaml,Lua等语言实现良好的浏览器运行时。Pyodide还与Iodide等网络优先工具实现了集成。

Pyodide定义了一个集成级别,用来实现与其他语言及工具的集成:

第一级别:字符串输出,可以作为基本控制台REPL(read-eval-print-loop)。

第二级别:支持将基本数据类型(数字,字符串,数组和对象)转换为JS或从JS转换。

第三级别:在客户语言和JS之间共享类实例(带方法的对象)。这允许Web API访问。

第四级别:在客户语言和JS之间共享科学计算相关类型(n维数组和数据框)。

结论

Pydodide提供了我们一种很酷的科学数据编程和用户体验。虽然目前还处于实验性概念验阶段,但是我们已经可以考虑将其做为日常数据科学工作的选择,并尝试给它的完善壮大添砖加瓦。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20190417A0DI5U00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券