C# 启动数千名后台工作人员的正确方法?

C# 启动数千名后台工作人员的正确方法?,c#,C#,我编写了一个程序,扫描网络中大约10000台计算机的正常运行时间、活动用户、空闲时间和ping。 这个节目表演得很好。主要是在3分钟内检查所有电脑。 但最近,这个项目一直停滞不前。它已完成所有任务,但不会退出。 我启动了所有后台工作人员,如下所示: foreach (DataRow computer in computerTable.Rows) { //Added check to see if computer is in

我编写了一个程序,扫描网络中大约10000台计算机的正常运行时间、活动用户、空闲时间和ping。 这个节目表演得很好。主要是在3分钟内检查所有电脑。 但最近,这个项目一直停滞不前。它已完成所有任务,但不会退出。 我启动了所有后台工作人员,如下所示:

foreach (DataRow computer in computerTable.Rows)
                {
                    //Added check to see if computer is in inputlist for inputfilemode
                    if (!inputFileMode || (inputFileMode && computerList.Contains(computer["ComputerName"].ToString())))
                    {
                        BackgroundWorker bw = new BackgroundWorker();
                        //Determine background jobs
                        bw.DoWork += bw_DoWork;
                        bw.RunWorkerCompleted += bw_RunWorkerCompleted;

                        bw.RunWorkerAsync(computer); //Start background worker
                        numberOfWorkers++;
                    }
                }


                int lastNr = 0;
                int skipHangingJobsCounter = 0;
                do
                {
                    lastNr = numberOfWorkers;
                    Thread.Sleep(1000);

                    Console.WriteLine("Tijd: " + DateTime.Now.ToString("yyyyMMdd-HH:mm:ss") + " #Jobs queued: " + numberOfWorkers.ToString() + " Jobs/sec: " + (lastNr - numberOfWorkers).ToString() + " -ForcedShutdowns: " + forcedReboots.ToString() + " -MSIEXEC Exceptions: " + machinesMSI.ToString()); //Report progress
                    if (lastNr - numberOfWorkers == 0)
                    {
                        skipHangingJobsCounter++;
                        if (skipHangingJobsCounter > 30) break; //Safety breakout if a worker hangs
                    }
                    else
                    {
                        skipHangingJobsCounter = 0;
                    }

                    //Timing break
                    double minutesRunning = DateTime.Now.Subtract(startOfJob).TotalMinutes;
                    if (minutesRunning > 13)
                    {
                        Console.WriteLine("Job is running for 14 minutes. Job will be cancelled. Jobs queued remaining: " + numberOfWorkers.ToString());
                        break;
                    }

                } while (numberOfWorkers > 0); //Wait till all jobs are finished
我想知道:这是启动和跟踪所有后台工作的最有效方式吗?创建列表数组是否更好? 我想那会占用很多记忆,是不是

在do_work部分,我有很多WMI查询,比如正常运行时间等。我的程序是否会因为挂起WMI查询而不退出?还有人做过这个实验吗

所以基本上我有两个问题:

1-我是否以有效/正确的方式启动后台工作人员

2-线程中的WMI调用是否可能导致程序无法退出

更新:

我重新编写了如下代码。现在大约快了3倍。我仍然使用1名后台工作人员,但仅此而已,因此我可以对主线程提供反馈。它的工作方式我认为:)

主线程:

                    BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += bw_DoWork;
                bw.RunWorkerCompleted +=bw_RunWorkerCompleted;
                bw.RunWorkerAsync();

                int lastNr = numberOfWorkers;
                do
                {
                    lastNr = numberOfWorkers;
                    Thread.Sleep(1000); //Give feedback every second

                    Console.WriteLine("Tijd: " + DateTime.Now.ToString("yyyyMMdd-HH:mm:ss") + " #Jobs queued: " + numberOfWorkers.ToString() + " Jobs/sec: " + (lastNr - numberOfWorkers).ToString() + " -ForcedShutdowns: " + forcedReboots.ToString() + " -MSIEXEC Exceptions: " + machinesMSI.ToString()); //Report progress

                    //Timing break
                    double minutesRunning = DateTime.Now.Subtract(startOfJob).TotalMinutes;
                    if (numberOfWorkers < 3)
                    {
                        //We are waiting for 3 last workers. Give feedback which 3 thse are
                        foreach (Task t in taskArray)
                        {
                            if (t.Status == TaskStatus.Running)
                            {
                                Console.WriteLine("Waiting for " + taskList[t.Id]);
                            }
                        }
                    }
                    if (minutesRunning > 13)
                    {
                        Console.WriteLine("Job is running for 14 minutes. Job will be cancelled. Jobs queued remaining: " + numberOfWorkers.ToString());
                        break;
                    }

                } while (!jobDone); //Wait till all jobs are finished

与此相反,您可以更好地使用一个预定义的方法来检查是否所有任务都已结束。您的代码非常容易出错,并且可能会关闭整个应用程序。为什么要为每台计算机启动一个线程?一万线?这对我来说似乎太过分了

我的建议是使用任务而不是背景工作者。如果您有网络I/O,您很可能会等待,从而提高总体性能。只要
任务。当所有的
任务完成时,你就会注意到它们准备好了


另一种方法是使用Parralell库。您可以
parralle.Foreach
查看计算机列表,将其最大限制为16台左右,NET framework将为您完成所有的循环和检查。

在for loops中使用异步方法不是一个好主意,为什么您需要为每台计算机启动backgroundworker???让几个工人来处理您的computerTable.Rows怎么样?您的“computerTable.Rows”可以是一个队列。代码本身是完全稳定的,并且执行它所做的事情。这里是控制台上的一些输出。它不会启动10000个线程。据我所知,他们在排队。然后根据处理能力进行处理:找到的计算机数量:9596 Tijd:20160104-23:00:02#排队的作业数:9591个作业/秒:4-强制关机:0-MSIEXEC异常:0 Tijd:20160104-23:00:03#排队的作业数:9589个作业/秒:2-强制关机:0-MSIEXEC异常:0 Tijd:20160104-23:00:04#排队的作业数:9584个作业/秒:5-你能吗详细说明一下?背景工作者不是为我做这件事吗?我是说。这三个选项在处理过程中有什么区别?使用任务有什么区别?所以我只是用Tasl的开头来代替BackGroundWorker的开头?你能给我一个这么多后台线程/作业的示例吗?。现在,它大约在3分钟内完成这项工作。我想还不错。你认为任务的速度会更快吗?谢谢。我想我会在数组中使用Task选项。
        static void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        JobLauncher();
    }

    static void JobLauncher()
    {


        foreach (DataRow computer in computerTable.Rows)
        {
            //Added check to see if computer is in inputlist for inputfilemode
            if (!inputFileMode || (inputFileMode && computerList.Contains(computer["ComputerName"].ToString())))
            {
                Task t = Task.Factory.StartNew(() => CheckComputer(computer));
                taskList.Add(t.Id, computer["ComputerName"].ToString());
                taskArray.Add(t);

                numberOfWorkers++;
            }
        }

        Task.WaitAll(taskArray.ToArray());
    }