gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:13:51 24 4
gpt4 key购买 nike

我正在编写一个程序,将 csv 文件从“队列”文件夹移动到“处理”文件夹,然后启动名为 import.exe 的第三方进程,将 csv 文件路径作为参数。 Import.exe 是一项长时间运行的任务。

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

我的问题是我被选项淹没了,无法理解我是否应该用 background threads 来解决这个问题。或 parallel 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.WaitAll() 才能读取结果。因此,即使提前完成,它也必须等待运行时间最长的任务。

我想我需要尝试循环创建异步进程,也许是使用任务,但我不明白如何作为后台进程执行此操作,以便我可以让服务计时器在需要时检查进程数创造更多。

最佳答案

首先想到的代码改进是删除计时器并将其替换为 System.IO.FileSystemWatcherCreated 事件的事件处理程序.这样,您的代码就不需要管理哪些文件之前在队列中以及哪些新文件已经到达。通常情况下,更少的代码 = 更少的问题。

其次,认真对待“任务”一词暗示在 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# - 在 Windows 服务中异步运行外部进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32041296/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com