• 控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化


    控件进程化,32位程序做大内存消耗时存在内存不够用时,特此记录解决方案,控件进程化,模块进程化...

    文章尾部提供完整demo下载

    前端时间公司做了图片视频分析处理的项目,图片支持4k,6k甚至勉强支持8k;因为处理的方式很多,各模块之前不能切换后销毁,用户需要来回切换的,针对这个问题,每个模块都会加载图片,图片过大后程序内存告急,且程序是32位的,即使开启了大内存(32位开启大内存)的支持依然不是很好的解决,内存占用过高很容易被360告警,所以项目上最后的解决方案就是进程化各个模块!


    通俗点讲就是,主进程启动后,会再启动子进程,子进程上会加载局部模块,附属于主进程,主进程退出后,子进程也终止,且子进程悬浮在主进程界面之上,所以例如打开遮罩时,需要发送命令到子进程,子进程自己再开启遮罩才能解决。


    公司封装了几个dll,服务于快捷进程化开发,为此我精简成2个库Cal.Wpf.Part、Cal.Wpf.PartHost

    Cal.Wpf.Part  辅助代码

    Cal.Wpf.PartHost 子进程依赖的启动程序exe,如果有多个,该程序会生成多个按进程分

    先大致看下效果:

    一个主进程,2个子进程

    下面是所有相关的dll

    实现原理:主程序启动后,传递窗口句柄并启动子程序,设置子程序的所有者句柄为主程序的,让其绑定在一起;程序之间利用TcpChannel实现数据通讯,特别啰嗦一句就是子程序永远悬浮于主程序之上。


    下面开始针对demo进行使用说明:

    1、引用Cal.Wpf.Part.dll、Cal.Wpf.PartHost.exe

    2、针对自定义的控件创建**Host.xaml(承载)、**Patrt.cs(辅助类)

    3、**Host.xaml 引用 Cal.Wpf.Part.dll,并显示占位

     1 <UserControl x:Class="ProcessDemo.CustomUserControlHostControl"
     2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     6              xmlns:part="clr-namespace:Cal.Wpf.Part;assembly=Cal.Wpf.Part"
     7              xmlns:local="clr-namespace:ProcessDemo"
     8              mc:Ignorable="d" 
     9              d:DesignHeight="450" d:DesignWidth="800">
    10     <Grid>
    11         <part:PartHostControl Name="partHost" />
    12     </Grid>
    13 </UserControl>
     1 using Cal.Wpf.Part.Remoting;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 using System.Windows;
     8 using System.Windows.Controls;
     9 using System.Windows.Data;
    10 using System.Windows.Documents;
    11 using System.Windows.Input;
    12 using System.Windows.Interop;
    13 using System.Windows.Media;
    14 using System.Windows.Media.Imaging;
    15 using System.Windows.Navigation;
    16 using System.Windows.Shapes;
    17 
    18 namespace ProcessDemo
    19 {
    20     /// <summary>
    21     /// UserControlHostControl.xaml 的交互逻辑
    22     /// </summary>
    23     public partial class CustomUserControlHostControl : UserControl, IDisposable
    24     {
    25         public CustomUserControlHostControl()
    26         {
    27             InitializeComponent();
    28         }
    29 
    30         ~CustomUserControlHostControl()
    31         {
    32             Dispose();
    33         }
    34 
    35         public void Dispose()
    36         {
    37             partHost.Dispose();
    38         }
    39 
    40         /// <summary>
    41         /// 收到进程的事件推送时
    42         /// </summary>
    43         public event MessageEventHandler ReceiveCommand
    44         {
    45             add
    46             {
    47                 partHost.ReceiveCommand += value;
    48             }
    49             remove
    50             {
    51                 partHost.ReceiveCommand -= value;
    52             }
    53         }
    54 
    55         /// <summary>
    56         /// 设置在独立进程中运行的控件
    57         /// </summary>      
    58         /// <param name="parentWindowHandler">父窗口句柄</param>
    59         public void InitPartControl(IntPtr parentWindowHandler)
    60         {
    61             partHost.InitPartControl(typeof(CustomUserControlPart), parentWindowHandler);
    62         }
    63 
    64         /// <summary>
    65         /// 发送消息
    66         /// </summary>
    67         /// <param name="msg"></param>
    68         public void SendMsg(string msg)
    69         {
    70             partHost.SendCommand(new ProcessMessage()
    71             {
    72                 Body = msg,
    73                 Command = 1
    74             });
    75         }
    76     }
    77 }

    4、 **Patrt.cs实现接口IPart

     1 using Cal.Wpf.Part;
     2 using System;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 using System.Windows;
     8 
     9 namespace ProcessDemo
    10 {
    11     public class CustomUserControlPart : IPart
    12     {
    13         /// <summary>
    14         /// 逻辑主控件
    15         /// </summary>
    16         private CustomUserControl control;
    17 
    18         /// <summary>
    19         /// 向主进程发消息时
    20         /// </summary>
    21         public event Cal.Wpf.Part.Remoting.MessageEventHandler SendCommand;
    22 
    23         /// <summary>
    24         /// 进程调用,需要支援释放了
    25         /// </summary>
    26         /// <returns></returns>
    27         public void Dispose()
    28         {
    29             if (control != null)
    30             {
    31                 control.SendMsg -= Control_SendMsg;
    32             }
    33         }
    34 
    35         /// <summary>
    36         /// 收到主进程消息时
    37         /// </summary>
    38         /// <param name="message"></param>
    39         public void ExecuteCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
    40         {
    41             if (message == null || message.Body == null) return;
    42 
    43             control.SetMsg(message.Body.ToString());
    44         }
    45 
    46         /// <summary>
    47         /// 进程调用,获取当前插件的展示界面
    48         /// </summary>
    49         /// <returns></returns>
    50         public FrameworkElement GetPartControl()
    51         {
    52             if (control == null)
    53             {
    54                 control = new CustomUserControl();
    55                 control.SendMsg += Control_SendMsg;
    56             }
    57             return control;
    58         }
    59 
    60         /// <summary>
    61         /// CustomUserControl 需要先外部进程发送消息时
    62         /// </summary>
    63         /// <param name="sender"></param>
    64         /// <param name="e"></param>
    65         private void Control_SendMsg(object sender, Tuple<int, string> e)
    66         {
    67             SendCommand?.Invoke(new Cal.Wpf.Part.Remoting.ProcessMessage()
    68             {
    69                 Command = e.Item1,
    70                 Body = e.Item2
    71             });
    72         }
    73 
    74         public void Initialize()
    75         {
    76             //加载CustomUserControl 之前需要做的事情,可以在这里写,比如加载皮肤dll等...
    77         }
    78     }
    79 }

    5、真实的自定义控件再原有的逻辑里,需要处理和主程序的消息通讯,因为当前控件是渲染在子控件上的

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Diagnostics;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 using System.Windows;
     9 using System.Windows.Controls;
    10 using System.Windows.Data;
    11 using System.Windows.Documents;
    12 using System.Windows.Input;
    13 using System.Windows.Media;
    14 using System.Windows.Media.Imaging;
    15 using System.Windows.Navigation;
    16 using System.Windows.Shapes;
    17 
    18 namespace ProcessDemo
    19 {
    20     /// <summary>
    21     /// CustomUserControl.xaml 的交互逻辑
    22     /// </summary>
    23     public partial class CustomUserControl : UserControl
    24     {
    25         public CustomUserControl()
    26         {
    27             InitializeComponent();
    28 
    29             if (!DesignerProperties.GetIsInDesignMode(this))
    30             {
    31                 pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
    32             }
    33         }
    34 
    35         /// <summary>
    36         /// 发送消息时
    37         /// </summary>
    38         public event EventHandler<Tuple<int, string>> SendMsg;
    39 
    40         /// <summary>
    41         /// 发送消息到主进程
    42         /// </summary>
    43         /// <param name="sender"></param>
    44         /// <param name="e"></param>
    45         private void Button_Click(object sender, RoutedEventArgs e)
    46         {
    47             SendMsg?.Invoke(this, new Tuple<int, string>(1, msg.Text));
    48         }
    49 
    50         /// <summary>
    51         /// 收到主进程的消息时
    52         /// </summary>
    53         /// <param name="msg"></param>
    54         public void SetMsg(string msg)
    55         {
    56             Dispatcher.Invoke(() =>
    57             {
    58                 msgstr.Text = $"收到主进程发来的消息:{msg}";
    59             });
    60         }
    61     }
    62 }

    6、最后就是在主进程上,把**Host占位,且在恰当的时候初始化子进程即可

     1 <Window x:Class="ProcessDemo.MainWindow"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6         xmlns:local="clr-namespace:ProcessDemo"
     7         xmlns:uc="clr-namespace:ProcessDemo.UC"
     8         WindowStartupLocation="CenterScreen"
     9         mc:Ignorable="d"
    10         Title="控件进程化Demo" Height="300" Width="400">
    11     <Grid>
    12         <DockPanel Margin="5">
    13             <Grid DockPanel.Dock="Top">
    14                 <StackPanel>
    15                     <TextBlock Text="我是主进程上的" />
    16                     <TextBlock x:Name="pid"/>
    17                     <StackPanel Orientation="Horizontal">
    18                         <TextBox x:Name="msg" Width="100" VerticalAlignment="Center" />
    19                         <Button Content="发消息给子进程" Margin="2" Click="Button_Click" />
    20                     </StackPanel>
    21                 </StackPanel>
    22             </Grid>
    23             <Grid DockPanel.Dock="Top">
    24                 <TextBlock Text="收到子进程消息时:..." x:Name="msgstr" />
    25             </Grid>
    26             <Grid DockPanel.Dock="Bottom">
    27                 <!--子进程2-->
    28                 <uc:UserControlHost Margin="10" x:Name="hostcontrol2" Height="50" />
    29             </Grid>
    30             <Grid>
    31                 <!-- 子进程存放位置 -->
    32                 <local:CustomUserControlHostControl x:Name="hostcontrol" Margin="10" />
    33             </Grid>
    34         </DockPanel>
    35     </Grid>
    36 </Window>
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Diagnostics;
     5 using System.Linq;
     6 using System.Text;
     7 using System.Threading.Tasks;
     8 using System.Windows;
     9 using System.Windows.Controls;
    10 using System.Windows.Data;
    11 using System.Windows.Documents;
    12 using System.Windows.Input;
    13 using System.Windows.Interop;
    14 using System.Windows.Media;
    15 using System.Windows.Media.Imaging;
    16 using System.Windows.Navigation;
    17 using System.Windows.Shapes;
    18 
    19 namespace ProcessDemo
    20 {
    21     /// <summary>
    22     /// MainWindow.xaml 的交互逻辑
    23     /// </summary>
    24     public partial class MainWindow : Window
    25     {
    26         public MainWindow()
    27         {
    28             InitializeComponent();
    29 
    30             if (!DesignerProperties.GetIsInDesignMode(this))
    31             {
    32                 pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
    33                 hostcontrol.ReceiveCommand += Hostcontrol_ReceiveCommand;
    34                 Loaded += MainWindow_Loaded;
    35             }
    36         }
    37 
    38         /// <summary>
    39         /// 窗口加载后
    40         /// </summary>
    41         /// <param name="sender"></param>
    42         /// <param name="e"></param>
    43         private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    44         {
    45             //获取当前句柄
    46             var parentWnd = Window.GetWindow(this);
    47             var winHelper = new WindowInteropHelper(parentWnd);
    48             IntPtr parentWindowHandler = winHelper.EnsureHandle();
    49 
    50             //初始化子进程
    51             hostcontrol.InitPartControl(parentWindowHandler);
    52             hostcontrol2.InitPartControl(parentWindowHandler);
    53         }
    54 
    55         /// <summary>
    56         /// 当收到子进程发来消息时
    57         /// </summary>
    58         /// <param name="message"></param>
    59         /// <returns></returns>
    60         private Cal.Wpf.Part.Remoting.ProcessMessage Hostcontrol_ReceiveCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
    61         {
    62             if (message == null || message.Body == null) return null;
    63 
    64             msgstr.Dispatcher.Invoke(() =>
    65             {
    66                 msgstr.Text = $"子进程发来消息:{message.Body.ToString()}";
    67             });
    68             return null;
    69         }
    70 
    71         /// <summary>
    72         /// 发给子进程
    73         /// </summary>
    74         /// <param name="sender"></param>
    75         /// <param name="e"></param>
    76         private void Button_Click(object sender, RoutedEventArgs e)
    77         {
    78             hostcontrol.SendMsg(msg.Text);
    79         }
    80     }
    81 }

    完整demo,有需要的可以移步下载,下面是解决方案摘要

     

  • 相关阅读:
    windows7上使用docker容器
    centos7 docker镜像加速器配置
    用列表生成器打印九九乘法表
    -bash: wget: command not found的两种解决方法
    centos7 Dockerfile安装nginx
    centos6.5关闭防火墙命令
    centos7开机启动tomcat7
    centos7安装tomcat7
    CentOS7防火墙firewalld
    poj_3662 最小化第k大的值
  • 原文地址:https://www.cnblogs.com/xuling-297769461/p/12767369.html
Copyright © 2020-2023  润新知