我写了一个程序,扫描网络中的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());
}
答案 0 :(得分:5)
而不是所有这些,您可以更好地使用预定义的方法来检查所有任务是否已经结束。您的代码如果非常容易出错并且可能会关闭整个应用程序。为什么为每台计算机启动1个线程? 10.000个主题?这对我来说似乎有点过分了。
我的建议是使用任务而不是后台工作人员。如果您有网络I / O,则最有可能await
,从而提高整体性能。只需Task.WhenAll
他们,你就会注意到他们准备好了。
另一种方法是使用Parrallel库。您可以Parrallel.Foreach
计算机列表,将它们调整到最多16个左右,.NET框架将完成所有循环并检查您。