Follow comments

0.10.0rc
Yu Yang 8 years ago
parent 8c4176a261
commit 952f8c139d

@ -8,9 +8,6 @@ Paddle需要一个多语言接口这个接口需要做到:
* 不同语言的接口适应不同语言的特性
* 例如Java与Python的错误处理是直接扔出来Exception而对于golang错误处理应该使用返回值。
我们可以将计算相关的代码使用C/C++来完成而将逻辑结构相关的代码交由其他更高级的语言完成。不同开发语言具有不同的优势领域。使用多种语言混合开发Paddle可以增加Paddle的开发效率。
## 基本要求
Paddle的多语言接口实现包括一下几个方面:
@ -25,8 +22,10 @@ Paddle的多语言接口实现包括一下几个方面:
### 使用动态库来分发Paddle
* Paddle的链接方式比较复杂(使用了--whole-archieve)如果使用了静态库分发那么要求使用Paddle库的人按照Paddle的要求链接Paddle这通常比较复杂。
* 编译型语言例如C/C++使用静态库和动态库难度差不多。但是含有解释器的语言例如python或者java基本上只能够调用动态库。
* Paddle的链接方式比较复杂
* Paddle链接静态库使用了GCC的--whole-archieve参数它要求使用Paddle静态库的二进制在链接参数中指定`--whole-archieve paddle_xxx_lib --no-whole-archive`。且这个链接参数是GCC独有的。对于clang或者msvc参数会不同。这增加了用户使用Paddle静态库的难度。
* 编译型语言例如C/C++使用静态库和动态库难度差不多。但是含有解释器的语言,例如[Python](http://stackoverflow.com/questions/19560594/how-to-import-static-library-in-python)或者[Java](http://stackoverflow.com/questions/24493337/linking-static-library-with-jni),调用动态库远比调用静态库方便。
* 解释性语言实际运行的二进制是解释器本身如果调用静态库只能将静态库与解释器链接。例如对于Java来说便是将静态库加入JVM中。这对于通常的Java的开发者来说是不常见的做法。
### 动态库中不嵌入任何其他语言的解释器
@ -44,6 +43,8 @@ Paddle的多语言接口实现包括一下几个方面:
* 由于C++编译器没有[名字修饰](https://en.wikipedia.org/wiki/Name_mangling#C.2B.2B)的规范不同版本的编译器之间对于同一段C++代码生成的符号可能不一致。而多语言接口需要直接读取生成的二进制(动态库),需要有稳定的导出符号。
* C语言是有导出符号的标准的并且在常见的平台上都是ABI调用标准的。
* 大多数语言都支持使用C语言API
* 使用C99而不使用C89是因为C99支持[Fixed-width integer types](https://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types)和[Boolean type](https://en.wikipedia.org/wiki/C_data_types#Boolean_type)。
* 使用C99而不使用C11的原因是[C11](https://en.wikipedia.org/wiki/C11_(C_standard_revision))并没有Paddle特别需要的特性且C99相对于C11使用更加广泛。
### 不导出Paddle内部的结构体、类仅仅使用`void*`指针作为类型的句柄(handler)
@ -51,15 +52,24 @@ Paddle的多语言接口实现包括一下几个方面:
* 在C-API中使用`void*`来表示Paddle内部类。再在每一个API中自己检查类型。
```C
// in Paddle.h
typedef void* paddle_matrix;
extern "C" paddle_error getShape(paddle_matrix mat, uint64_t* height, uint64_t* width);
// in matrix.cpp
struct PaddleMatrix {
int type;
paddle::MatrixPtr mat;
};
// in Paddle.h
typedef void* PD_Matrix;
extern "C" PD_Error getShape(PD_Matrix, uint64_t* height, uint64_t* width);
paddle_error get_shape(paddle_matrix m, uint64_t* height, uint64_t* width) {
PaddleMatrix* realMat = (PaddleMatrix*)(m);
...
}
```
### 不使用SWIG这种代码生成器而是手写多语言绑定
@ -67,8 +77,10 @@ extern "C" PD_Error getShape(PD_Matrix, uint64_t* height, uint64_t* width);
* [SWIG](http://www.swig.org/)是一个多语言接口的代码生成器。他的目标是使用C/C++写代码SWIG直接读取C/C++的头文件,生成各种语言的绑定代码。
* 对于多语言接口SWIG需要写一个interface文件。这个文件具有独特的语法学习成本高。且增加一个第三方语言就需要对这个第三方语言增加一些定义。有的时候interface文件的写法非常[tricky](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/api/Paddle.swig#L36)。社区贡献代码学习成本高。
* SWIG暴露的接口保留了C++的接口样式,很难保证多语言代码风格的一致性。(函数命名,错误处理)
* 因为SWIG在第三方语言中暴露的函数名类名和C++中完全一致。C++的命名风格并不能适应其他第三方语言。如果使用SWIG我们需要将在interface文件里将大量的`SomeCppClass`重命名成`some_python_class`,或者`SomeGoTypes`。
* 对于不同语言错误处理的方式也不尽相同。例如对于Java或者Python最常见的错误处理方式是Exception而对于Golang错误处理方式是返回值。而SWIG只能简单的暴露C++接口,无法做到对于各种语言错误处理方式的适配。
* 对于大多数语言直接使用C语言的.h并不困难。例如Python的[cffi](https://cffi.readthedocs.io/en/latest/overview.html#simple-example-abi-level-in-line)或者[Cython](http://cython.org/), golang的[cgo](https://golang.org/cmd/cgo/)。
* swig支持的语言或者解释器有局限。例如对于Python使用SWIG只支持CPython解释器而不支持PyPy解释器。
* SWIG支持的语言或者解释器有局限。例如对于Python使用SWIG只支持CPython解释器而不支持PyPy解释器。
## 原因列表
@ -78,9 +90,9 @@ extern "C" PD_Error getShape(PD_Matrix, uint64_t* height, uint64_t* width);
| 使用动态库 | 不使用静态库 | 解释型语言只能调用动态库Paddle静态库链接复杂 |
| 不嵌入其他语言解释器 | 不嵌入Python解释器 | Paddle C++目前嵌入Python解释器会导致不同版本Python在一个进程里的bug |
| 不引用其他动态库 | | Paddle一个动态库可以在任何Linux系统上运行 |
| 使用C99做接口 | 不使用C++做接口 | C有标准的ABIC99是目前C最广泛的使用标准(而不是C11和C89) |
| 使用C99做接口 | 不使用C++做接口 | C有标准的ABIC99是目前C最广泛的使用标准且C99支持bool类型和定长整数(uint64_t等)类型 |
| 使用void*作为类句柄 | 不显示的写每个类具体包含什么| 实现简单,并且让接口脱离实现细节 |
| 手写多语言绑定 | 不使用SWIG | 写SWIG很tricky社区参与难。SWIG生成的代码不能保证多语言代码风格的一致性 |
| 手写多语言绑定 | 不使用SWIG | 使用SWIG需要多语言绑定的开发人员熟练掌握SWIG配置社区参与困难。SWIG生成的代码不能保证多语言代码风格的一致性 |
## 简单实现

Loading…
Cancel
Save