SourceGenerator的应用: .Net多进程开发库 - Juxtapose


背景

进程间通讯属于老生常谈的话题,可能已经有很多的通信示例代码,但在实际使用中需要做的东西还比较多。例如协议定制、消息收发、进程管理等都需要实现,进阶需求可能还需要实现回调函数、取消等。
个人在工作中恰好遇到了相关需求,然后在网上搜了一下,只找到两个.net下多进程相关的库(有可能是搜索方式不对)
https://github.com/tmds/Tmds.ExecFunction
https://github.com/CyAScott/AppDomainAlternative/
但并不满足需求,不能进程复用,或者不能方便的进行回调、取消。于是乎进行手写相关代码。
在手写了两三个相似的项目后,觉悟到重复的劳动是可以进一步省略的,于是进行了封装,产生了该项目 - Juxtapose 基于 SourceGenerator 的硬编码 .Net进程运行库。只需要几行额外的代码就能使现有代码(*)支持多进程运行,进程复用,支持LinuxWindows,支持回调委托CancellationToken,支持调试子进程(*)。无显式的运行时反射调用和动态构造类。
好处很多,那么代价是什么呢?

  • 简单的一次方法调用将会经历数据传输以及至少四次序列化或反序列化;对比进程内方法调用来说是巨大的损耗。
  • 方法参数只能是简单的数据类型(委托和CancellationToken除外,它们进行了特化处理),不能传递有行为的对象。
  • 跨进程的异常信息将被包裹,需要自行解析;
  • 调用堆栈将会变复杂;

综上,使用时需要能够接受和处理上述情况。

Juxtapose早期版本已经在生产环境进行了长时间的使用验证,但新的Release版本暂时还没有;

相关技术

SourceGenerator

源生成器 - SourceGenerator 已经推出有一段时间了,参见官方公告 Introducing C# Source Generators
官方简介:
源生成器是一项 C# 编译器功能,使 C# 开发人员能够在编译用户代码时进行检查,并动态生成新的 C# 源文件,以添加到用户的编译中。 通过这种方式,你的代码可以在编译过程中运行并检查你的程序以生成与其余代码一起编译的其他源文件。
使用SourceGenerator可以在编译时生成代码,避免运行时反射,提高运行效率,使FullAOT成为可能,代码运行逻辑也更加直观。不在此处进行过多描述,已经有不少的文章对其进行了介绍,可以随便搜索到,官方也有完善的示例代码。

相关资源:

进程间通讯

通讯方式很多,可以参考文章 c#多进程通讯,今天,它来了
Juxtapose默认实现了命名管道通信(有需求可以自行实现其他方式进行替换),默认使用命名管道的主要原因是它由.net原生集成、支持双工通信、跨平台。

使用场景

以下为实际使用场景,更多场景请自行结合实际需求。

  • 某组件不允许在一个进程内创建多个实例,无法并发;
  • 某组件使用了过多内存、内存泄漏、内存释放不及时,导致进程被杀、Pod重启、服务中断;
  • 某组件执行某耗时操作时,不支持取消操作,且占用大量CPU/内存资源,影响程序运行;
  • 某组件直接操作内存,会偶发性出现非法访问,导致进程退出;

Nuget包介绍

1. Intro

基于 SourceGenerator 的硬编码 .Net进程运行库。

包列表

名称介绍
Juxtapose运行时库,封装通用的功能
Juxtapose.SourceGenerator源代码生成器,用于代码生成
Juxtapose.VsDebuggerVisualStudio调试附加包,用于子进程调试

2. Features

  • 可以为类型接口静态类生成代理,无需手动编写RPC相关代码,即可多进程运行;
  • 编译时生成所有代码,运行时无显式的反射调用和动态构造;
  • 支持委托CancellationToken类型的方法参数(其余类型未特殊处理,将会进行序列化,目前回调委托不支持嵌套和CancellationToken);
  • 支持LinuxWindows(其它未测试);
  • 支持调试子进程(Windows&&VisualStudio Only);

注意事项

  • 目前参数不支持定义为父类型,实际传递子类型,序列化时将会按照定义的类型进行序列化和反序列化,会导致具体类型丢失;
  • 目前所有的参数都不应该在方法完成后进行保留,CancellationToken委托等在方法完成后会被释放;

3. Requirement

  • .Net5.0+(其它版本没有尝试过)

4. 使用方法

4.1 引用包

<ItemGroup>
  <PackageReference Include="Juxtapose" Version="1.0.0" />
  <PackageReference Include="Juxtapose.SourceGenerator" Version="1.0.0" />
</ItemGroup>

4.2 建立上下文

4.2.1 创建上下文类型,并使用 [Illusion] 特性指定要生成的类型

[Illusion(typeof(Greeter), typeof(IGreeter), "Juxtapose.Test.GreeterAsIGreeterIllusion")]
public partial class GreeterJuxtaposeContext : JuxtaposeContext
{
}

示例代码将为Greeter生成IGreeter接口的代理类型Juxtapose.Test.GreeterAsIGreeterIllusion

Note!!!

  • 必须继承JuxtaposeContext
  • 必须标记partial关键字;

4.2.2 [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")]
  • 生成从IoC容器获取的接口代理类型,如下示例生成 Juxtapose.Test.IGreeterIllusionFromIoCContainer 类型(此时Context类需要实现IIoCContainerProvider接口,并提供有效的IServiceProvider
[Illusion(typeof(IGreeterFromServiceProvider), generatedTypeName: "Juxtapose.Test.IGreeterIllusionFromIoCContainer", fromIoCContainer: true)]

4.3 添加入口点

Main方法开始处添加入口点代码,并使用指定上下文

await JuxtaposeEntryPoint.TryAsEndpointAsync(args, GreeterJuxtaposeContext.SharedInstance);

到此已完成开发,创建类型Juxtapose.Test.GreeterAsIGreeterIllusion的对象,并调用其方法,其实际逻辑将在子进程中运行;

5. 调试子进程(Windows&&VisualStudio Only)

5.1 引用调试包

在Host项目文件中添加包引用

<ItemGroup Condition="'$(Configuration)' == 'Debug'">
  <PackageReference Include="Juxtapose.VsDebugger" Version="1.0.0" />
</ItemGroup>

建议和示例代码一样,添加条件引用,只在Debug环境下引用调试包

5.2 添加入口点

Main方法开始处添加调试入口点代码

JuxtaposeDebuggerAttacher.TryAttachToParent(args);

在代码中打上断点,运行时将会正确命中断点(只在 VisualStudio2022 17.0.5 && Win11 21TH2 中进行了测试,理论上是通用)

6. 工作逻辑

SourceGenerator在编译时生成代理类型,封装通信消息。在创建代理类型对象时,会自动创建子进程,并在子进程中创建目标类型的对象,使用命名管道进行进程间通信,使用System.Text.Json进行消息的序列化与反序列化。更多技术细节可以参考源代码。

链接

源代码: https://github.com/stratosblue/juxtapose
Nuget: https://www.nuget.org/packages/Juxtapose

引用来源:https://www.cnblogs.com/internalnet/archive/2022/01/25/15840625.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:C# 读取txt文件生成Word文档
下一篇:ManualResetEvent实现线程的暂停与恢复
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

SourceGenerator应用: .Net进程开发 - Juxtapose
使用.NET 6开发TodoList应用(22)——实现缓存
使用.NET 6开发TodoList应用(31)——实现基于Github Actions和ACICI/CD
使用.NET 6开发TodoList应用(27)——实现APISwagger文档化
使用.NET 6开发TodoList应用(24)——实现基于JWTIdentity功能
使用.NET 6开发TodoList应用(26)——实现Configuration和Option强类型绑定
使用.NET 6开发TodoList应用(6)——使用MediatR实现POST请求
YESWEB POS开发调试
EFCore官方扩展
使用.NET 6开发TodoList应用(12)——实现ActionFilter
使用.NET 6开发TodoList应用(15)——实现查询搜索
使用.NET 6开发TodoList应用(9)——实现PUT请求
使用.NET 6开发TodoList应用(14)——实现查询过滤
使用.NET 6开发TodoList应用(28)——实现应用程序健康检查
使用.NET 6开发TodoList应用(23)——实现请求限流
YES-WEB快速开发框架,.NET WEB开发平台,高效web项目开发框架
使用.NET 6开发TodoList应用(7)——使用AutoMapper实现GET请求
使用.NET 6开发TodoList应用(25)——实现RefreshToken
使用.NET 6开发TodoList应用(16)——实现查询排序
使用.NET 6开发TodoList应用(29)——实现静态字符串本地化功能

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划 容差配置 SAP事务码 SAP基础 TCODE Basis 事务代码 MMNR 编号区间 采购实操 组织架构 OMSF SAP实操 FI配置
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码