Has*_*zar 5 .net c# linq backgroundworker
我正在尝试一个项目中的数据库密集型任务.这是一个演练:
我们需要搜索我们的工作人员数据库,我们称之为Locums,并为特定工作找到一个.当我们决定处理x个作业时,此过程开始.因此,只需单击一个按钮,我们就可以使用该ProcessJobBatch()方法进行处理.但是,此方法仅针对非常有限数量的Locums进行处理.因此,填充调度程序控件需要不到10秒.现在,一旦提供了有限数量的Locums,我们就需要运行后台任务来检查Locums的其余部分.大约有1250个!
因此,一旦ProcessJobBatch()完成,一BackgroundWorker,BackgroundWorkerMoreLocums,熄灭.现在,这个工作人员基本上做了一个简单的循环:对于每个工作,请通过整个1250名员工.这需要太长时间.我需要使用替代策略来计划这个,我不能使用ATM或者我需要为内部for-each循环显示辅助进度条.
更多说明:我们每天多次导入一批作业(10到70).导入批处理后,应用程序会指示登录用户"首选"查找新创建的作业.用户已经有他最喜欢的位置列表(1到20).他希望首先在他最喜欢的工作中分配工作.这是通过完成的ProcessJobBatch().但是,有两种情况会阻止那里的流量:
因此,我最终得到了一个与每个Locum匹配作业的场景.
问题: 第二个BackgroundWorker可以在BackgroundWorker的DoWork中运行吗?我第二次扫描错了吗?
环境: Windows 7 Pro 64位,Visual Studio 2010,C#,.NET 4.0和Windows窗体
private void ButtonPreferenceFind_Click(object sender, EventArgs e) {
if (LookUpBatches.EditValue != null) {
JobBatch JobBatchSelected = DbContext.JobBatches.FirstOrDefault(job_batch=> job_batch.OID == LookUpBatches.EditValue.ToString());
if (JobBatchSelected != null && JobBatchSelected.Jobs.Count(condition => condition.JobStatusID == 1) > 0) {
if (XtraMessageBox.Show(String.Format("Are you sure to process {0} job(s)?", JobBatchSelected.Jobs.Count(condition => condition.JobStatusID == 1)), Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
ProcessJobBatch(JobBatchSelected);
IEnumerable<Job> SpecificJobs = from req_jobs in JobBatchSelected.Jobs
where req_jobs.JobStatusID == 1
select req_jobs;
ProgressBarControlPreferenceFinder.EditValue = 0;
ProgressBarControlPreferenceFinder.Properties.Minimum = 0;
ProgressBarControlPreferenceFinder.Properties.Maximum = SpecificJobs.Count() - 1;
BackgroundWorkerMoreLocums.RunWorkerAsync(SpecificJobs);
} else {
LookUpBatches.Focus();
}
} else {
XtraMessageBox.Show("Unable to retrieve the selected batch or the batch has no processable jobs.", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
LookUpBatches.Focus();
}
} else {
XtraMessageBox.Show("Select a batch first.", Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
LookUpBatches.Focus();
}
}
#region Background Searching
private void BackgroundWorkerMoreLocums_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
try {
e.Result = GetTableData(e.Argument);
}
catch (Exception ex) {
XtraMessageBox.Show("Background Error: " + ex.Message, "Excite Engine 2", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Result = ex;
}
}
private void BackgroundWorkerMoreLocums_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
// only display progress, do not assign it to grid
ProgressBarControlPreferenceFinder.Increment(e.ProgressPercentage);
}
private void BackgroundWorkerMoreLocums_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) {
if (e.Result is DataTable) {
//dataGridView1.DataSource = e.Result as DataTable;
}
else if (e.Result is Exception) {
}
}
private DataTable GetTableData(Object JobList) {
DataTable ResultDataTable = new DataTable();
ResultDataTable.Columns.Add();
IEnumerable<Job> JobBatchSelected = (IEnumerable<Job>)JobList;
IEnumerable<Locum> LeftOverLocums = from lefties in DbContext.Locums
//where SchedulerMatrixStorage.Resources.Items.Select(res => (long)res.Id).ToList().Contains(lefties.OID) == false
select lefties;
int NumOfJobsProcessed = 0;
List<KeyValuePair<long, TemporaryPreferenceFindLocum>> AlreadyPrefferedLocums = new List<KeyValuePair<long, TemporaryPreferenceFindLocum>>();
foreach (Job oneJob in JobBatchSelected) {
foreach (Locum oneLocum in LeftOverLocums) {
if (DbContext.Availabilities.Any(check => check.LocumID == oneLocum.OID && check.AvailableDate == oneJob.JobDate && check.AvailabilityStatusID == 1)) {
//This Locum can do this job
//Now check if he/she has been just alloted
if (AlreadyPrefferedLocums.Any(search => search.Key == oneLocum.OID && search.Value.JobDate == oneJob.JobDate) == false) {
//No? Cool!
//Add to the list to prevent double allocation
AlreadyPrefferedLocums.Add(new KeyValuePair<long, TemporaryPreferenceFindLocum>(oneJob.OID, new TemporaryPreferenceFindLocum(oneJob.JobDate, oneJob.OID, oneLocum.OID, oneLocum.FirstName + " " + oneLocum.LastName)));
}
else {
continue;
}
}
else {
//Not marked as Avaliable on the required job date...
continue;
}
}
NumOfJobsProcessed++;
BackgroundWorkerMoreLocums.ReportProgress((int)(NumOfJobsProcessed * 100F / (JobBatchSelected.Count() - 1)));
}
return ResultDataTable;
}
#endregion
Run Code Online (Sandbox Code Playgroud)
Joã*_*elo 13
A BackgroundWorker可以从DoWork另一个的处理程序中启动BackgroundWorker,但您需要了解使用此类方案的后果.当您从主UI线程启动后台工作DoWork程序时,处理程序在线程池线程上执行,而ProgressChanged并RunWorkerCompleted在主UI线程上执行,这使您可以安全地与Windows窗体控件进行交互.
当您从主UI线程启动工作程序时,可以保证这种情况,因为它会获取SynchronizationContext该线程上的可用工具,并由windows窗体infra-structure初始化.
但是,当您从DoWork另一个worker 的处理程序启动后台worker时,您将从缺少同步上下文的线程池线程启动它,导致ProgressChanged和RunWorkerCompleted处理程序也在线程池线程上执行而不是在您的主UI线程中执行使您在这些处理程序中与Windows窗体控件进行交互时不安全.
让一个后台线程产生新的后台线程是很常见的.如果您在后台线程上扫描列表并处理另一个线程上的每个列表项,我认为这不是问题.
在这种情况下,在另一个内部没有后台工作者.只有后台工作者启动其他线程.
你应该考虑的事情 -
如果您处理该事件,请注意您在已完成的事件处理程序中执行的操作.
考虑为小任务运行这么多线程的性能影响.您应该考虑使用PLINQ或并行任务,以便.Net可以处理输入的分区和结果的合并,从而为您提供最佳性能.