MPI Library for .Net

今天整点.Net。因为在某个业余小项目中,需要尽可能榨干硬件性能,以满足尽可能大的可访问数据范围。

发现在.Net中并行计算一般使用System.Threading.Task.Parallel,但实际开发中,似乎只能处理到1G左右的数据就会溢出,机器整个状态似乎只是在摸鱼。并且拥有多台物理机器的时候并不能共享计算资源。

第一步,将多线程的程序改为多进程+多线程。输入是一个文件路径列表,是一堆pdf。需要使用OCR识别pdf内嵌图片中的内容,输入大模型完成校准,输出校准后的txt,后续成为构建向量数据库用的基础数据。

多线程好办,直接用Parallel干就好了。多进程多少有些麻烦。主要困难的点在于进程间数据共享。解决这种困难第一时间去找开源库,然鹅并没有这种的。因为写python的时候joblib里面Parallel一下,delayed一个表达式搞定的事情,在.Net并没有类似的东西。随即写了一个。叫做MPILibrary。实际上真的要做MPI很复杂,有专门一个学科研究这东西,这里姑且用这个名字了。

发布在nuget了,MIT License,直接可以搜来使用,自用商用都行。

NuGet Gallery | MPILibrary 1.0.4

源码开放在Github

lu1770/MPILibrary (github.com)

基本做法比较简单,第一步,开一个可执行程序,在Main函数开头加上子进程处理逻辑:

if (ProcessParallel.IsSubProcess())
{
    ProcessParallel.Handle();
    return;
}

  

第二步,定义一个静态方法,本来想做成支持lambda表达式失败了,先用静态方法好了。

class Runner
{
    public static object Run(string id)
    {
        return new
        {
            CommandLineArgs = Environment.GetCommandLineArgs(),
            Message = $"input is {id}, process id is {Process.GetCurrentProcess().Id}",
            Time=DateTime.Now.ToShortTimeString()
        };
    }
}

第三步,传入待处理数据,启动执行。

// Generate Items
var items = Enumerable.Range(1, 200).Select(i => Guid.NewGuid().ToString());

// Show MaxProcessLimit
Console.WriteLine($"Start {ProcessParallel.MaxProcessLimit}");

// Run
List<object> results = ProcessParallel.ForEach(items, Runner.Run).ToList();

// Show Results
Console.WriteLine(JsonConvert.SerializeObject(results, Formatting.Indented));

这里items中每个元素会开一个专门的进程执行Run,这样单进程内存上限差不多是1.2G。

处理完成之后,从Run返回的结果会作为元素存放在results里面,这里出来的结果是乱序的,对顺序敏感的话,可以设计一个特别的keypair的返回结构自行实现完成后排序。

MaxProcessLimit这个用于控制进程数的,默认使用当前机器CPU内核数,防止实际编程忽略此设置,实现又过于奔放,把机器玩没了的情况。当然,如果实际items特别少,机器性能又超强的情况下使用int.MaxValue也未尝不可。实际测试下来默认值效果最好,默认值1.5倍会有鼠标键盘操作无响应的情况,酌情使用把。

进程间通信使用JSON格式的,所以输入输出的格式需要可以被JSON序列化的结构。

未来版本,考虑使用以太网实现多物理机的IPC,这样多台机器组合并行,通过修改一个配置项,获得相当可观的计算能力。

老板们有需要直接提issue把,有用的会抽空去做。

 

 

 

posted on 2024-02-01 08:32  ZhengyaoLu  阅读(49)  评论(0)    收藏  举报

导航