进程间通讯属于老生常谈的话题,可能已经有很多的通信示例代码,但在实际使用中需要做的东西还比较多。例如协议定制、消息收发、进程管理等都需要实现,进阶需求可能还需要实现回调函数、取消等。
个人在工作中恰好遇到了相关需求,然后在网上搜了一下,只找到两个.net下多进程相关的库(有可能是搜索方式不对)
https://github.com/tmds/Tmds.ExecFunction
https://github.com/CyAScott/AppDomainAlternative/
但并不满足需求,不能进程复用,或者不能方便的进行回调、取消。于是乎进行手写相关代码。
在手写了两三个相似的项目后,觉悟到重复的劳动是可以进一步省略的,于是进行了封装,产生了该项目 - Juxtapose 基于 SourceGenerator
的硬编码 .Net
多进程
运行库。只需要几行额外的代码就能使现有代码(*)支持多进程运行,进程复用,支持Linux
、Windows
,支持回调委托
和CancellationToken
,支持调试子进程(*)。无显式的运行时反射调用和动态构造类。
好处很多,那么代价是什么呢?
综上,使用时需要能够接受和处理上述情况。
源生成器 - SourceGenerator
已经推出有一段时间了,参见官方公告 Introducing C# Source Generators。
官方简介:源生成器是一项 C# 编译器功能,使 C# 开发人员能够在编译用户代码时进行检查,并动态生成新的 C# 源文件,以添加到用户的编译中。 通过这种方式,你的代码可以在编译过程中运行并检查你的程序以生成与其余代码一起编译的其他源文件。
使用SourceGenerator
可以在编译时生成代码,避免运行时反射,提高运行效率,使FullAOT成为可能,代码运行逻辑也更加直观。不在此处进行过多描述,已经有不少的文章对其进行了介绍,可以随便搜索到,官方也有完善的示例代码。
相关资源:
通讯方式很多,可以参考文章 c#多进程通讯,今天,它来了。
Juxtapose默认实现了命名管道通信(有需求可以自行实现其他方式进行替换),默认使用命名管道的主要原因是它由.net原生集成、支持双工通信、跨平台。
以下为实际使用场景,更多场景请自行结合实际需求。
基于 SourceGenerator
的硬编码 .Net
多进程
运行库。
名称 | 介绍 |
---|---|
Juxtapose | 运行时库,封装通用的功能 |
Juxtapose.SourceGenerator | 源代码生成器,用于代码生成 |
Juxtapose.VsDebugger | VisualStudio调试附加包,用于子进程调试 |
类型
、接口
、静态类
生成代理,无需手动编写RPC相关代码,即可多进程
运行;委托
和CancellationToken
类型的方法参数(其余类型未特殊处理,将会进行序列化,目前回调委托
不支持嵌套和CancellationToken
);Linux
、Windows
(其它未测试);Windows
&&VisualStudio
Only);CancellationToken
、委托
等在方法完成后会被释放;<ItemGroup> <PackageReference Include="Juxtapose" Version="1.0.0" /> <PackageReference Include="Juxtapose.SourceGenerator" Version="1.0.0" /></ItemGroup>
[Illusion]
特性指定要生成的类型[Illusion(typeof(Greeter), typeof(IGreeter), "Juxtapose.Test.GreeterAsIGreeterIllusion")]public partial class GreeterJuxtaposeContext : JuxtaposeContext{}
示例代码将为Greeter
生成IGreeter
接口的代理类型Juxtapose.Test.GreeterAsIGreeterIllusion
;
Note!!!
JuxtaposeContext
;partial
关键字;[Illusion]
的多种用法Juxtapose.Test.GreeterIllusion
类型,且不继承接口(静态类型相同用法)[Illusion(typeof(Greeter))]
Juxtapose.Test.GreeterAsIGreeterIllusion
类型且继承IGreeter
接口[Illusion(typeof(Greeter), typeof(IGreeter))]
Juxtapose.Test.HelloGreeter
类型[Illusion(typeof(Greeter), generatedTypeName: "Juxtapose.Test.HelloGreeter")]
Juxtapose.Test.IGreeterIllusionFromIoCContainer
类型(此时Context类需要实现IIoCContainerProvider
接口,并提供有效的IServiceProvider
)[Illusion(typeof(IGreeterFromServiceProvider), generatedTypeName: "Juxtapose.Test.IGreeterIllusionFromIoCContainer", fromIoCContainer: true)]
在Main
方法开始处添加入口点代码,并使用指定上下文
await JuxtaposeEntryPoint.TryAsEndpointAsync(args, GreeterJuxtaposeContext.SharedInstance);
Juxtapose.Test.GreeterAsIGreeterIllusion
的对象,并调用其方法,其实际逻辑将在子进程中运行;Windows
&&VisualStudio
Only)在Host项目文件中添加包引用
<ItemGroup Condition="'$(Configuration)' == 'Debug'"> <PackageReference Include="Juxtapose.VsDebugger" Version="1.0.0" /></ItemGroup>
Debug
环境下引用调试包在Main
方法开始处添加调试入口点代码
JuxtaposeDebuggerAttacher.TryAttachToParent(args);
VisualStudio2022 17.0.5
&& Win11 21TH2
中进行了测试,理论上是通用)SourceGenerator
在编译时生成代理类型,封装通信消息。在创建代理类型对象时,会自动创建子进程,并在子进程中创建目标类型的对象,使用命名管道进行进程间通信,使用System.Text.Json
进行消息的序列化与反序列化。更多技术细节可以参考源代码。
源代码: https://github.com/stratosblue/juxtapose
Nuget: https://www.nuget.org/packages/Juxtapose