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