如何在Windows上使用Python for .NET进行多进程处理?

13

现在我正在开发C#应用程序,在Windows上运行。 其中一些进程是用Python编写的,并通过pythonnet(Python for .NET)调用。 这些进程需要大量计算,所以我想并行执行它们。

它们是CPU密集型的,可以独立处理。

据我所知,有两种可能的实现方式:

  1. 启动多个Python运行时
    第一种方法是启动多个Python解释器,但似乎不可行。 因为pythonnet显然只能管理一个由静态方法PythonEngine.Initialize()初始化的解释器。
    来自Python.NET文档:

    嵌入者的重要提示: Python不是自由线程的,并使用全局解释器锁定来允许多线程应用程序安全地与Python解释器交互。有关此更多信息,请参见www.python.org网站上的Python C-API文档。
    在将Python嵌入托管应用程序中时,必须像在将Python嵌入C或C ++应用程序中时那样管理GIL。
    在调用Python.Runtime命名空间提供的任何对象或API之前,调用代码必须通过调用PythonEngine.AcquireLock方法获取Python全局解释器锁(GIL)。唯一的例外是PythonEngine.Initialize方法,该方法可以在启动时调用而无需获取GIL。

  2. 在Python中使用multiprocessing包
    另一种方法是使用multiprocessing包。 根据Python文档,在Windows上运行代码时,以下语句对于确保生成有限进程是必要的:
    if __name__ == "__main__":
    但是,由于它被嵌入到.NET中,所以用Python编写的函数被视为模块的一部分。 例如,下面的代码可执行,但会无限生成进程。

//C#
static void Main(string[] args)
    {
        using (Py.GIL())
        {
            PythonEngine.Exec(
                "print(__name__)\n" + //output is "buitlins"
                "if __name__ == 'builtins':\n" +
                "   import test_package\n" +  //import Python code below
                "   test_package.async_test()\n"
                );
        }
    }
# Python
import concurrent.futures

def heavy_calc(x):
    for i in range(int(1e7) * x):
        i*2

def async_test():
    # multiprocessing
    with concurrent.futures.ProcessPoolExecutor(max_workers=8) as executor:
        futures = [executor.submit(heavy_calc,x) for x in range(10)]
        (done, notdone) = concurrent.futures.wait(futures)
        for future in futures:
            print(future.result())

有没有解决以上问题的好主意?任何评论将不胜感激。提前致谢。


使用ThreadPoolExecutor代替ProcessPoolExecutor怎么样? - Evk
只是为了提及一次 - 是否有可能将你的Python代码翻译成C#,并且能够使用易于使用的线程池等功能而感到满意?:) "无限生成进程"。这些进程至少能够完成它们的工作吗?它们能够做好事情吗?如果是的,那么你唯一的问题就是无休止地生成进程。我问这个问题,是因为我没有完全理解出了无限进程生成之外还出了什么问题。 - Tobias Theel
@Evk 正如我在帖子中提到的,计算过程是CPU密集型的,因此ProcessPool很适合,因为ThreadPoolExecuter由于Python的GIL无法使其更快。请参见https://dev59.com/t3M_5IYBdhLWcg3wymY0 - sfb
1
@TobiasTheel Python的东西包括很多高级计算,比如机器学习,因此翻译可能需要很长时间。没错,我的唯一问题是“无休止的进程生成”。如果运行帖子中的代码,也许可以至少完成它们的工作,但会无限地生成进程,导致我的Windows系统死机。根据Python文档所述,我们必须通过if name == "main":来保护“入口点”。我想知道如何在嵌入式应用程序中实现这一点。 - sfb
我不是很理解。你发布的这两个代码块如何结合在一起?上面的代码块是否调用下面的代码块?如果是这样的话:为什么你要在C#中制作主可执行文件,而不是在Python中导入pythondotnet并从Python中调用你的C#代码呢? - hansaplast
显示剩余3条评论
1个回答

3

对于每个Python调用, 1.创建一个应用程序域 2.在应用程序域中创建一个任务,以异步方式运行Python。

由于它是独立的AppDomains,静态方法将是独立的。

创建和使用AppDomain很耗费资源,如果您需要同时运行大量调用,则无法进行,但听起来您可能只需要异步运行少量进程。


直到现在我才了解AppDomain,谢谢。看起来它能够工作,但我不确定有多少进程对应着极大的量(当然,我知道这取决于许多因素)。我会检查它是否顺利运行。 - sfb
当然。尝试需要一些时间,请稍等片刻。AppDomain的使用似乎与预期的不同,但值得尝试。 - sfb
@sfb,你是否已经通过使用单独的AppDomain解决了你的问题?我现在也在我的WPF应用程序中遇到了完全相同的问题。 - Amaury Levé

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接