我写了一个程序,扫描网络中的10.000台计算机的正常运行时间,活动用户,空闲时间和ping.该计划表现很好.主要是在大约3分钟内检查所有计算机.但最近,该计划一直在冻结.它完成了所有任务,但不会退出.我像这样启动所有BackGroundWorkers:
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
我想知道:这是启动和跟踪所有后台工作的最有效方式吗?最好是创建一个List数组吗?我认为这会占用大量内存,不是吗?
在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
背景工作
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()); }
Patrick Hofm.. 5
而不是所有这些,您可以更好地使用预定义的方法来检查所有任务是否已经结束.您的代码如果非常容易出错并且可能会关闭整个应用程序.为什么为每台计算机启动1个线程?10.000个主题?这似乎有点矫枉过正.
我的建议是使用任务而不是后台工作人员.如果您有网络I/O,则最有可能的await
是,提高整体性能.只是Task.WhenAll
他们,你会注意到他们准备好了.
另一种方法是使用Parrallel库.你可以Parrallel.Foreach
在计算机列表中将它们调整到最多16个左右,.NET框架将完成所有循环并检查你.
而不是所有这些,您可以更好地使用预定义的方法来检查所有任务是否已经结束.您的代码如果非常容易出错并且可能会关闭整个应用程序.为什么为每台计算机启动1个线程?10.000个主题?这似乎有点矫枉过正.
我的建议是使用任务而不是后台工作人员.如果您有网络I/O,则最有可能的await
是,提高整体性能.只是Task.WhenAll
他们,你会注意到他们准备好了.
另一种方法是使用Parrallel库.你可以Parrallel.Foreach
在计算机列表中将它们调整到最多16个左右,.NET框架将完成所有循环并检查你.