Pythonnet这个屌爆的专案的出现,使得我们可以用一种新的方式,让C#可以和Python之间进行互操作。但是它的设定和部署可能有点问题,真的是这样吗?
本文我会介绍Python.Included这个专案,它不但优雅的解决了这个问题,并且让.NET开发者可以轻松愉快的让.NET与Python进行互操作。作为概念的证明,我将使用Numpy.Net进行展示,它是一个.NET标准库,它为Python的Numpy提供了一个强型别API,并且使用它并不需要在Windows上安装Python。

开发人员从Numpy.NET的强型别API中获益,与动态API不同,后者支援Visual Studio的IntelliSense功能,可以显示原始的Numpy文件。
问题是什么?
每个人可能都安装了不同版本的Python,有一些人用Python 2.7,其他一些人用Python 3.5,3.6甚至3.7。当你使用pythonnet的时候,针对Python的每个小版本,它必须使用不同的配置进行编译,而且该版本的Python必须安装,这样程式码才可以执行。所以如果你在团队里工作,每个人就必须配置完全相同的Python环境。但拿我们的SciSharp团队来说,情况就已经不是这样的了。如果你想部署你的.NET应用,你首先必须部署Python,从开发人员角度来讲,这很闹心。然而,如果你正在搞机器学习和人工智能,尽管微软和SciSharp都付出了很大努力,但目前你还是无法完全避免Python的使用。如果你看一下正在使用pythonnet的专案的列表,你会发现很多AI领域的公司当前都在使用.NET与Python进行连线。
Python.Included 前来救援
如果你可以很简单的引用一个Nuget包,并在无需手动修改的情况下,一切都会自动的配置好,假如可以达到这种程度,你会感觉怎么样?这就是我建立Python.Included的愿景,Python.Included可以把packages python-3.7.3-embed-amd64.zip包含在它的程式集里,这这样就允许你可以通过Nuget来有效的引用Python了。为了证明它能正常工作,并可以快速提供所有的NumSharp中仍然缺少的Numpy功能,我建立了基于Python.Included的Numpy.NET这个专案。概念验证:Numpy.NET
Numpy.NET为Numpy提供了强型别的包装函式,这意味着您完全不需要使用dynamic关键字,但这部分我会在另一篇文章中深入讨论。今天的重点是介绍 Numpy.NET 如何使用 Python.Included 来按需自动部署Python和Numpy以便对它们进行呼叫。这是Numpy将在幕后实际执行的设定程式码。这些都不需要你来操作。一旦你使用了它的一个函式:
var a = np.array(new [,] {{1, 2}, {3, 4}});,
Numpy.dll 就会设定好嵌入的Python发行版,而它是从你本机home目录里的程式集里解压缩出来的(如果还没安装过的话)。
var installer = new Python.Included.Installer();
installer.SetupPython(force:false).Wait();
下一步(如果在之前的执行中还没完成)它将解压缩 numpy pip wheel,而numpy pip wheel 是作为嵌入的资源打包到了Numpy.dll里的并其安装到了Python安装档案里。
installer.InstallWheel(typeof(NumPy).Assembly, "numpy-1.16.3-cp37-cp37m-win_amd64.whl").Wait();
最后,pythonnet执行时被初始化了,Numpy也被汇入进来了,可供后续使用。
PythonEngine.Initialize();
Py.Import("numpy");
这些都是在幕后发生的,使用Numpy.dll的使用者根本不用担心本地的Python安装。事实上,即使您已安装了任何版本的Python也无所谓。
效能注意事项
大家都知道pythonnet比较慢,因此您可能会问自己,使用pythonnet将Python库与.NET接在一起是否真的是一个好主意。一如既往,这要看情况而定。我的测试结果表明,与直接从Python呼叫Numpy相比,使用.net呼叫numpy的开销大约是它的4倍。需要澄清一下,这并不意味着Numpy.NET比python中的numpy慢四倍,这仅仅意味着通过pythonnet呼叫Numpy会有额外的开销。当然了,由于Numpy.NET呼叫的是Numpy,Numpy函式本身的执行时间是完全相同的。
开销是否是一个问题完全取决于实际用例。如果您在一个巢状循环中不断的在CLR和Python之间来回切换,那就可能会遇到问题。但大多数Python库的设计都都是为了提高效率,避免资料循环。Numpy允许您只使用一个呼叫就可以对数百万的阵列元素进行操作。Pytorch和Tensorflow允许您完全在GPU上执行操作。因此,如果正确使用,与处理大量资料时操作的执行时间相比,互操作开销可以忽略不计。
路线图
我知道现在有很多把Numpy移植到.NET上的方案和专案,例如使用IronPython。但是IronPython专案仍然只支援Python 2.7,而且专案进展非常缓慢。这就导致了依赖于python 3的库不能通过IronPython来获得和使用,而且这种情况在近期也不会有什么改变。我的重点是通过pythonnet为.NET提供更多的机器学习和人工智能库。SciSharp团队也在讨论如何研发出一个更快版本的pythonnet,从而避免使用天性缓慢的DynamicObject。
请尝试一下Numpy.NET,并让我知道它为你做了什么并且做的如何。如果有任何意见或建议,我将不胜感激,我希望我的工作能够帮助.NET机器学习社群成长和繁荣。





























