新北仑网站怎么做的,校园网站的建设作用,烟台网站建设工资,网站建设主要问题原标题#xff1a;30倍#xff01;使用Cython加速Python代码作者#xff1a;George Seif、Thomas Wolf、Lukas Frei编译#xff1a;116 | 公众号海外部前言你可能经常会一次又一次地听到关于Python的抱怨#xff0c;Python跑起来太慢了#xff01;与许多其他编程语言相比…原标题30倍使用Cython加速Python代码作者George Seif、Thomas Wolf、Lukas Frei编译116 | 公众号海外部前言你可能经常会一次又一次地听到关于Python的抱怨Python跑起来太慢了与许多其他编程语言相比Python的确很慢。有几种不同的方法可以使代码提速如果你的代码是纯Python。如果你有一个很大的for循环你只能使用它而不能放入矩阵中因为数据必须按顺序处理那该怎么办有没有办法加快Python本身的速度来吧看看Cython文末下载Cython相关书籍什么是CythonCython的核心是Python和C / C之间的一个中间步骤。它允许N你编写纯Python代码只需要做一些小修改然后将其直接翻译成C代码。Cython 语言是 Python 的一个超集它包含有两种类型的对象Python 对象就是我们在常规 Python 中使用到的那些对象诸如数值、字符串、列表和类实例等等。Cython C 对象就是那些 C 和 C 对象诸如双精度、整型、浮点数、结构和向量它们能够由 Cython 在超级高效的低级语言代码中进行编译。你对Python代码所做的唯一调整就是向每个变量添加类型信息。通常我们可以像这样在Python中声明一个变量x 0.5使用Cython我们为该变量添加一个类型cdef float x 0.5这告诉Cython变量是浮点数就像我们在C中所做的一样。对于纯Python变量的类型是动态确定的。Cython中类型的显式声明使其转为C代码成为可能因为显式类型声明需要。有很多办法来测试、编译和发布 Cython 代码。Cython 甚至可以像 Python 一样直接用于 Jupyter Notebook 中。有很多办法来测试、编译和发布 Cython 代码。Cython 甚至可以像 Python 一样直接用于 Jupyter Notebook 中。安装Cython只需要一行pippip install cython使用Cython需要安装C语言编译器因此安装过程会根据你当前的操作系统而有所不同。对于Linux通常使用GNU C编译器(gncc)。对于Mac OS你可以下载Xcode以获取gncc。而Windows 桌面系统下安装C编译器会更复杂。使用 %load_ext Cython 指令在 Jupyter notebook 中加载 Cython 扩展。然后通过指令 %%cython我们就可以像 Python 一样在 Jupyter notebook 中使用 Cython。如果在执行 Cython 代码的时候遇到了编译错误请检查 Jupyter 终端的完整输出信息。大多数情况下可能都是因为在 %%cython 之后遗漏了 - 标签(比如当你使用 spaCy Cython 接口时)。如果编译器报出了关于 Numpy 的错误那就是遗漏了 import numpy。如果你要在在IPython中使用Cython首先介绍一下IPython Magic命令。Magic命令以百分号开头通常有2种类型单行Magic由单个表示并且仅在一行输入上操作。单元格Magic用两个表示并在多行输入上操作。首先运行下列语句引入Cython%load_ext Cython然后当运行Cython代码时我们需要加入以下Cython 代码%%cython然后就可以愉快地使用Cython了。Cython中的类型使用Cython时变量和函数有两组不同的类型。对于变量我们有cdef int a, b, ccdef char *scdef float x 0.5 (single precision)cdef double x 63.4 (double precision)cdef list namescdef dict goals_for_each_playcdef object card_deck注意所有这些类型都来自C / C !def - 常规Python函数仅从Python调用。cdef - 仅限Cython函数接受Python对象或C值作为参数并且可以返回Python对象或C值cdef函数不能直接在Python中调用。cpdef - 接受Python对象或C值作为参数并且可以返回Python对象或C值。我们可以方便的向C代码传递和返回结果Cython会自动为我们做相应的类型转化。了解了Cython类型之后我们就可以直接实现加速了!如何使用Cython加速代码我们要做的第一件事是设置Python代码基准用于计算数字阶乘的for循环。原始Python代码如下deftest(x):y 1fori inrange(x1):y * ireturnyCython的实现过程看起来非常相似。首先确保Cython代码文件具有 .pyx 扩展名。这些文件将被 Cython 编译器编译成 C 或 C 文件再进一步地被 C 编译器编译成字节码文件。你也可以使用 pyximport 将一个 .pyx 文件直接加载到 Python 程序中importpyximport; pyximport.installimportmy_cython_module你也可以将自己的 Cython 代码作为 Python 包构建然后像正常的 Python 包一样将其导入或者发布。不过这种做法需要花费更多的时间特别是你需要让 Cython 包能够在所有的平台上运行。如果你需要一个参考样例不妨看看 spaCy 的安装脚本https://github.com/explosion/spaCy/blob/master/setup.py?sourcepost_page---------------------------最终 Python 解释器将能够调用这些字节码文件。对代码本身的惟一更改是我们已经声明了每个变量和函数的类型。cpdef int test(int x):cdef int y 1cdef int ifori inrange(x1):y * ireturny注意函数有一个cpdef来确保我们可以从Python调用它。另外看看我们的循环变量i是如何具有类型的。你需要为函数中的所有变量设置类型以便C编译器知道使用哪种类型接下来创建一个setup.py文件该文件将Cython代码编译为C代码fromdistutils.core importsetupfromCython.Build importcythonizesetup(ext_modules cythonize(run_cython.pyx))并执行编译python setup.py build_ext --inplaceBoom我们的C代码已经编译好可以使用了!你将看到在Cython代码所在的文件夹中拥有运行C代码所需的所有文件包括run_cython.c文件。如果你感兴趣可以查看一下Cython生成的C代码现在我们准备测试新的C代码查看下面的代码它将执行一个速度测试将原始Python代码与Cython代码进行比较。现在我们准备测试我们新的超快速C代码了查看下面的代码它执行速度测试以将原始Python代码与Cython代码进行比较。importrun_pythonimportrun_cythonimporttimenumber 10start time.timerun_python.test(number)end time.timepy_time end - startprint(Python time {}.format(py_time))start time.timerun_cython.test(number)end time.timecy_time end - startprint(Cython time {}.format(cy_time))print(Speedup {}.format(py_time / cy_time))Cython可以让你在几乎所有原始Python代码上获得良好的加速而不需要太多额外的工作。需要注意的关键是循环次数越多处理的数据越多Cython可以提供的帮助就越多。查看下表该表显示了Cython为不同的阶乘值提供的速度我们使用Cython获得了超过36倍的加速Cython在NLP中的加速应用当我们在操作字符串时要如何在 Cython 中设计一个更加高效的循环呢spaCy是个不错的选择spaCy 中所有的unicode字符串(the text of a token, its lower case text, its lemma form, POS tag label, parse tree dependency label, Named-Entity tags…)都被存储在一个称为StringStore的数据结构中它通过一个64位哈希码进行索引例如C类型的 uint64_t。StringStore对象实现了Python unicode字符串与 64 位哈希码之前的查找映射。它可以spaCy的任何地方和任意对象进行访问例如npl.vocab.strings、doc.vocab.strings或者span.doc.vocab.string。当某模块需要在某些标记上获得更快的处理速度时可以使用C语言类型的64位哈希码代替字符串来实现。调用StringStore查找表将返回与该哈希码相关联的Python unicode字符串。但是spaCy能做的可不仅仅只有这些它还允许我们访问文档和词汇表完全填充的C语言类型结构我们可以在Cython循环中使用这些结构而不必去构建自己的结构。spaCy拓展https://spacy.io/api/cython?sourcepost_page---------------------------建立一个脚本用于创建一个包含有 10 份文档的列表每份文档都大概含有 17 万个单词采用 spaCy 进行分析。当然我们也可以对 17 万份文档(每份文档包含 10 个单词)进行分析但是这样做会导致创建的过程非常慢所以我们还是选择了 10 份文档。我们想要在这个数据集上展开某些自然语言处理任务。例如我们可以统计数据集中单词「run」作为名词出现的次数(例如被 spaCy 标记为「NN」词性标签)。采用Python循环来实现上述分析过程非常简单和直观importurllib.requestimportspacywithurllib.request.urlopen(https://raw.githubusercontent.com/pytorch/examples/master/word_language_model/data/wikitext-2/valid.txt) asresponse:text response.readnlp spacy.load(en)doc_list list(nlp(text[:800000].decode(utf8)) fori inrange(10))这段代码至少需要运行 1.4 秒才能获得答案。如果我们的数据集中包含有数以百万计的文档为了获得答案我们也许需要花费超过一天的时间。我们也许能够采用多线程来实现加速但是在Python中这种做法并不是那么明智因为你还需要处理全局解释器锁(GIL)。在Cython中可以无视GIL的存在而尽情使用线程加速。但不能再使用Python中的字典和列表因为Python中的变量都自动带了锁(GIL)。还好Cython已经封装了C标准库中的容器dequelistmappairqueuesetstackvector。完全可以替代Python的dict, list, set等。我们使用Cython就可以解决这个但不能再使用Python中的字典和列表因为Python中的变量都自动带了锁(GIL)。还好Cython已经封装了C标准库中的容器dequelistmappairqueuesetstackvector。完全可以替代Python的dict, list, set等。另外请注意Cython也可以使用多线程Cython在后台可以直接调用OpenMP。https://cython.readthedocs.io/en/latest/src/userguide/parallelism.html?sourcepost_page---------------------------现在让我们尝试使用spaCy和Cython来加速 Python 代码。首先需要考虑好数据结构我们需要一个C类型的数组来存储数据需要指针来指向每个文档的 TokenC 数组。我们还需要将测试字符(「run」和「NN」)转成 64 位哈希码。当所有需要处理的数据都变成了C类型对象我们就可以以纯C语言的速度对数据集进行迭代。以下是被转换成Cython和spaCy的实现%%cython -importnumpyfromcymem.cymem cimport Poolfromspacy.tokens.doc cimport Docfromspacy.typedefs cimport hash_tfromspacy.structs cimport TokenCcdef struct DocElement:TokenC* cint lengthcdef int fast_loop(DocElement* docs, int n_docs, hash_t word, hash_t tag):cdef int n_out 0fordoc indocs[:n_docs]:forc indoc.c[:doc.length]:ifc.lex.lower word andc.tag tag:n_out 1returnn_outdefmain_nlp_fast(doc_list):cdef int i, n_out, n_docs len(doc_list)cdef Pool mem Poolcdef DocElement* docs mem.alloc(n_docs, sizeof(DocElement))cdef Doc docfori, doc inenumerate(doc_list):docs[i].c doc.cdocs[i].length (doc).lengthword_hash doc.vocab.strings.add(run)tag_hash doc.vocab.strings.add(NN)n_out fast_loop(docs, n_docs, word_hash, tag_hash)在Jupyter notebook上这段Cython代码运行了大概20毫秒比之前的纯Python循环快了大概80倍。使用Jupyter notebook单元编写模块的速度很可观它可以与其它 Python 模块和函数自然地连接在 20 毫秒内扫描大约 170 万个单词这意味着我们每秒能够处理高达 8 千万个单词。如果你已经了解C语言Cython还允许访问C代码而Cython的创建者还没有为这些代码添加现成的声明。例如使用以下代码可以为C函数生成Python包装器并将其添加到模块dict中。%%cythoncdef extern frommath.h:cpdef double sin(double x)Cython注意的坑1、.pyx中用CDEF定义的东西除类以外对的.py都是不可见的。2、.c中是不能操作C类型的如果想在.py中操作C类型就要在.pyx中从python对象转成C类型或者用含有set / get方法的C类型包裹类。3、虽然Cython能对Python的str和C的“char *”之间进行自动类型转换但是对于“char a [n]”这种固定长度的字符串是无法自动转换的。需要使用Cython的libc.string .strcpy进行显式拷贝。4、回调函数需要用函数包裹再通过C的“void *”强制转换后才能传入C函数。Cython相关资料(下载)0、其他https://cython.org/?sourcepost_page---------------------------1、官方文档2、参考书籍(文末下载)书籍下载在后台输入(严格大小写)责任编辑