ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

c# – 在Windows服务中异步运行外部进程

2019-05-19 19:06:05  阅读:213  来源: 互联网

标签:c asynchronous multithreading windows-services net-4-5


我正在编写一个将csv文件从“queue”文件夹移动到“processing”文件夹的程序,然后以csv文件路径作为参数启动名为import.exe的第三方进程. Import.exe是一个长期运行的任务.

我需要程序继续运行并检查队列中的新文件.出于这个原因,我选择了一个Windows服务应用程序,因为它将长期运行.

我的问题是我对选项感到不知所措,无法理解我是否应该用background threadsparallel programming解决这个问题,或者很可能是两者的结合.

到目前为止,我有这个代码只是同步运行.
您很快就会看到,我只是疯狂地解决流程而无需管理或检查完成情况.我已经注释掉了process.WaitForExit(),显然这是一个阻塞调用.

public int maxConcurrentProcesses = 10;
protected override void OnStart(string[] args)
    {
        // Set up a timer to trigger every minute.
        System.Timers.Timer timer = new System.Timers.Timer(60000);            
        timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
        timer.Start();
    }

private void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
    {            
        // How many instances of import.exe are running?
        Process[] importProcesses = Process.GetProcessesByName("import");
        int countRunning = importProcesses.Count();

        // If there are less than maxConcurrentProcesses, create as many as needed to reach maxConcurrentProcesses
        if (countRunning < maxConcurrentProcesses)
        {
            int processesToStart = maxConcurrentProcesses - countRunning;
            for (int i = 0; i < processesToStart; i++)
            {
                FireOffImport();
            }
        }
    }

private void FireOffImport()
    {
        // Get the first file returned from the Queue folder
        string filePathSource = GetNextCSVInQueue();

        if (filePathSource != "")
        {
            // …
            // commandArguments = create our arguments here
            // …        
            // Move the file to processing folder here
            // … 

            // Give a new process the import tool location and arguments
            ProcessStartInfo startInfo = new ProcessStartInfo(importLocation + "\\import.exe", commandArguments);
            try
            {
                Process process = Process.Start(startInfo);
                // process.WaitForExit(20000);
                // If the process has exited, there will be 4 csv files created in the same directory as the file.                  
            }
            catch (Exception ex)
            {
               // Deal with exception here
            }
       }
    }

我还尝试创建一个Task数组,并异步运行它们.但最后我仍然需要调用Task.WaitAll()才能读取结果.因此,即使提前结束,它也必须等待最长的运行任务.

我想我需要尝试循环创建可能使用任务的异步流程,但我不明白如何将其作为后台进程,这样我就可以让服务计时器检查进程数量是否需要创建更多.

解决方法:

您想到的代码的第一个改进是删除计时器并将其替换为System.IO.FileSystemWatcher和Created事件的事件处理程序.这样,您的代码无需管理之前队列中的哪些文件以及哪些新文件已到达.通常,减少代码=减少问题.

其次,单词“Task”认真地暗示要在1个System.IO.Tasks.Task实例中真正执行完整的导入任务,包括生成相应的导入流程实例并在完成后等待它退出.

如果您希望随时限制运行的导入进程数量,则可以使用调度程序替换调度程序,该调度程序允许与默认调度程序相比并行运行limits the amount of tasks.如果每个任务与1个导入程序实例关联,并且允许最多N个任务同时运行,则导入程序进程的最多N个实例.

下面的代码显示(以控制台应用程序的形式),上面描述的内容如何,​​减去提供的链接中涵盖的自定义调度程序.

using System.Threading.Tasks;

namespace ConsoleApplication4
{
    class Program
    {
        static string importerProcessName = "import.exe";
        static string RootFolder = @"E:\temp\A\";
        static string queuePath = System.IO.Path.Combine(RootFolder, "Queue" );
        static string processingPath = System.IO.Path.Combine(RootFolder, "Processing");
        static string donePath = System.IO.Path.Combine(RootFolder, "Done");
        static void Main(string[] args)
        {
            GrantFolders(); // Make sure we have all our folders ready for action...
            var watcher = new System.IO.FileSystemWatcher(queuePath, "*.txt");
            watcher.Created += watcher_Created;
            watcher.EnableRaisingEvents = true;
            System.Console.ReadLine();
        }
        static Task ProcessFile( string fileName )
        {
            Task task = new Task(() =>
            {
                System.Console.WriteLine("Processing: " + fileName);
                System.IO.File.Move(System.IO.Path.Combine(queuePath, fileName), System.IO.Path.Combine(processingPath, fileName));
                string commandLine = "-import " + System.IO.Path.Combine(processingPath, fileName);
                using (var importer = new System.Diagnostics.Process())
                {
                    importer.StartInfo = new System.Diagnostics.ProcessStartInfo(importerProcessName, commandLine);
                    importer.Start();
                    importer.WaitForExit(20000);
                    System.IO.File.Move(System.IO.Path.Combine(processingPath, fileName), System.IO.Path.Combine(donePath, fileName));
                    System.Console.WriteLine("Done with: " + fileName);
                }
            });
            return task;
        }
        static void watcher_Created(object sender, System.IO.FileSystemEventArgs e)
        {
            System.Console.WriteLine("Found in queue: " + e.Name);
            var task = ProcessFile(e.Name);
            task.Start();
        }

        private static void GrantFolders()
        {
            string[] paths = new string[] { queuePath, processingPath, donePath };
            foreach( var path in paths)
            {
                if(!System.IO.Directory.Exists(path))
                {
                    System.IO.Directory.CreateDirectory(path);
                }
            }
        }
    }
}

标签:c,asynchronous,multithreading,windows-services,net-4-5
来源: https://codeday.me/bug/20190519/1136877.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有