首页 > 系统相关 >c#多进程开发

c#多进程开发

时间:2023-09-08 19:46:51浏览次数:36  
标签:obj string stream c# 开发 进程 new 序列化 public

介绍

相比多线程开发,C#的多进程开发相对麻烦,无法像多线程一样对某个函数直接启动。只能将函数打包成exe文件,再使用process启动exe文件并传参,传入的参数必须序列化为字符串。

过程

1、构建执行函数

因为要将数据分进程处理,所以构建了一个函数,输入参数对象 bundleMerge,执行函数即可运行进程代码。

public static  void createBundle(bundleMerge bm){
    //业务代码
}

2、封装序列化类

输入的参数只能是字符串,因此将参数对象序列化,在序列化过程中使用各种第三方包都报错,最后找到一个序列化帮助类

/// <summary>
    /// 序列化帮助类
    /// </summary>
    public class SerializeHelper
    {
        /// <summary>
        /// 序列obj对象为base64字串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string Serialize(object obj)
        {
            if (obj == null)
                return string.Empty;

            try
            {
                var formatter = new BinaryFormatter();
                var stream = new MemoryStream();
                formatter.Serialize(stream, obj);
                stream.Position = 0;
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                stream.Close();
                return Convert.ToBase64String(buffer);
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("序列化{0}失败,原因:{1}", obj, ex.Message));
            }
        }

        /// <summary>
        /// 反序列化字符串到对象
        /// </summary>
        /// <param name="str">要转换为对象的字符串</param>
        /// <returns>反序列化出来的对象</returns>
        public static T Deserialize<T>(string str)
        {
            var obj = default(T);
            if (string.IsNullOrEmpty(str))
                return obj;

            try
            {
                var formatter = new BinaryFormatter();
                byte[] buffer = Convert.FromBase64String(str);
                MemoryStream stream = new MemoryStream(buffer);
                obj = (T)formatter.Deserialize(stream);
                stream.Close();
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("序列化{0}失败,原因:{1}", obj, ex.Message));
            }
            return obj;
        }
    }

3、构建exe程序

新建一个项目,项目类型修改为应用程序
image.png
在项目main函数中使用业务代码和反序列化后的参数作为传入对象:

    public class tiles2bundleEXE
    {

        static void Main(string[] args) {
            // 获取传递的JSON字符串
            string json = args[0];
            // 反序列化JSON字符串为对象
            Console.WriteLine(json);
            bundleMerge bm = SerializeHelper.Deserialize<bundleMerge>(json);
            //bundleMerge bm = JsonConvert.DeserializeObject<bundleMerge>(json);
            // 业务代码
            tiles2bundle.createBundle(bm);
            //执行完成后结束进程
            Environment.Exit(0);

        }
    }

生成解决方案后,得到exe文件
image.png

4、多进程帮助类

copy了一个多进程帮助类,用来控制进程数量和创建进程

public class ProcessHelper
    {
        public delegate void countHandler(int i);
        public event countHandler count;

        public  bool processRun(string processPath, List<string> listBundle)
        {
            int maxProcessCount = Environment.ProcessorCount;
            List<Task> taskItems = new List<Task>();
            Queue<string> collectPathItems = new Queue<string>();
            foreach (var item in listBundle)
            {
                collectPathItems.Enqueue(item);
            }
            string exeName = Path.GetFileName(processPath);
            Process[] processItems;
            int cursor = 0;
            while (!(collectPathItems.Count == 0 && taskItems.Count == 0))
            {
                foreach (Task taskItem in new List<Task>(taskItems))
                {
                    if (taskItem.Status == TaskStatus.Canceled || taskItem.Status == TaskStatus.Faulted || taskItem.Status == TaskStatus.RanToCompletion)
                    {
                        taskItems.Remove(taskItem);
                    }
                }
                // 如果collectPathItems.Count == 0,则不会有新的任务被添加进来,因此不需要执行下边其他代码。
                // 而只需要等待上边的任务完成跳出循环即可。
                if (collectPathItems.Count == 0)
                {
                    Thread.Sleep(5 * 1000);
                    continue;
                }
                
                processItems = Process.GetProcessesByName(exeName);
                if (processItems.Length >= maxProcessCount)
                {
                    Thread.Sleep(5 * 1000);
                    continue;
                }
                int dequeueCount = ((maxProcessCount - processItems.Length) > collectPathItems.Count) ? collectPathItems.Count : (maxProcessCount - processItems.Length);
                for (int i = 0; i < dequeueCount; i++)
                {
                    taskItems.Add(Task.Factory.StartNew(
                        (object mystate) =>
                        {
                            Process process = Process.Start(processPath, mystate.ToString());
                            process.WaitForExit();
                            count?.Invoke(0);
                        }
                       , collectPathItems.Dequeue())
                       );
                }
                // sleep 30 seconds...
                Thread.Sleep(5 * 1000);
                cursor++;

            }
            //循环等待进程运行完成
            processItems = Process.GetProcessesByName(exeName);
            while (processItems.Length  != 0)
            {
                Thread.Sleep(10 * 1000);
            }
            return true;
        }
    }

5、在form中使用多进程帮助类和exe对象

//新建一个列表,用来接收序列化后的参数对象
List<string> listPara = new List<string>();
foreach (var item in listBundle)
{
    listPara.Add(SerializeHelper.Serialize(item)   );
}
//将路径指向生成后的exe文件
string exePath = Environment.CurrentDirectory + "\\tiles2bundle.exe";
ProcessHelper ph = new ProcessHelper();
ph.count += new ProcessHelper.countHandler(ProcessChanged);
//使用帮助类运行
ph.processRun(exePath, listPara);

总结

在c#中构建一个多进程程序比较麻烦,不如python中直接pool.starmap启动进程池方便。

标签:obj,string,stream,c#,开发,进程,new,序列化,public
From: https://www.cnblogs.com/EVELE/p/17688408.html

相关文章

  • Alembic:Python数据库迁移工具
    Alembic是一款轻量型的数据库迁移工具,它与SQLAlchemy一起共同为Python提供数据库管理与迁移支持。Alembic的应用Alembic使用SQLAlchemy作为数据库引擎,为关系型数据提供创建、管理、更改和调用的管理脚本,协助开发和运维人员在系统上线后对数据库进行在线管理。同任何P......
  • [AGC058D] Yet Another ABC String
    [AGC058D]YetAnotherABCStringAtcoder:[AGC058D]YetAnotherABCString洛谷:[AGC058D]YetAnotherABCStringProblem给出\(a,b,c\),求由\(a\)个A,\(b\)个B,\(c\)个C构成的字符串数量,使得不存在子串ABC,BCA和CAB。\(1\leqa,b,c\leq10^6\)。Solution可能是......
  • 【题解】CF1854D Michael and Hotel
    交互题。考虑题意即为找到\(1\)所在内向基环树上的所有点。我们考虑我们怎么找到环上的点,我们考虑我们可以\(O(\logn)\)询问到一个环上的点,方法即为将\(k\)定为一个大数,然后二分点集。然后我们便可以在\(O(n\logn)\)的时间复杂度内找到所有环上的点(我们一会儿再讲怎......
  • C# 写入类型到文件Helper类
    usingSystem;usingSystem.IO;usingSystem.Text;namespaceControls.Helper{publicclassLoggerHelper{privatestaticobjecto=newobject();privatestaticstringGetLogFilePath(){stringfilePath=AppD......
  • C++多线程编程:包括多线程打印ABC、线程池实现等等
    #include<iostream>#include<thread>#include<mutex>#include<condition_variable>std::condition_variablecond;std::mutexprint_mutex;intflag=0;voidprint_thread(intnum){for(inti=0;i<10;i++)//循环{......
  • 【230908-16】▲ABC中,a=2,c=二倍根号2,C=45°,则S△ABC=?
    ......
  • 【230908-17】▲ABC中,b=2,B=30°,C=45°,则S△ABC=?(2013年全国II卷)
    ......
  • 无涯教程-JavaScript - IMLN函数
    描述IMLN函数以x+yi或x+yj文本格式返回复数的自然对数。复数的自然对数为-$$\ln(x+yi)=\ln\sqrt{x^2+y^2}+i\tan^{-1}\left(\frac{y}{x}\right)$$语法IMLN(inumber)争论Argument描述Required/OptionalInumberAcomplexnumberforwhichy......
  • C++之进化后的 const 分析
    @TOC前言从C演变而来的C++是一种功能更为丰富和面向对象的编程语言。在C++中,const关键字用于表示常量,其用法与C中的const有了一些进化和扩展。本文将探讨C到C++的const的进化,以及在C++中使用const的一些特性和用法。C语言中的constconst修饰的变量是只读的,本质上还是变量。const修......
  • 所以说,java的“方法”有点儿类似于C++的"函数"吧
    两个语言的区别就是,C++如果函数写在下面的话,要在上面注释:而java的方法若写在下面的话,要加static,然后不管怎样,前面一定要加public......