【发布时间】:2011-03-09 10:39:42
【问题描述】:
我正在一个项目中尝试一项非常密集的数据库任务。这是一个演练:
我们需要搜索我们称为 Locums 的工人数据库,并为特定工作找到一个。当我们决定处理 x 个作业时,此过程开始。因此,在单击按钮时,我们使用ProcessJobBatch() 方法进行处理。但是,此方法仅针对非常有限数量的 Locums 进行处理。因此,填充调度程序控件需要不到 10 秒的时间。现在,一旦为有限数量的 Locums 提供服务,我们需要运行一个后台任务来检查其余的 Locums。大约有 1250 个!
所以,一旦ProcessJobBatch() 完成,BackgroundWorker、BackgroundWorkerMoreLocums 就会消失。现在,这个工人基本上做了一个简单的循环:对于每个工作,遍历整个 1250 名员工。这需要的时间太长了。我需要使用 ATM 无法使用的替代策略来计划这一点,或者我需要为内部 for-each 循环显示辅助进度条。
更多说明:我们每天都会多次导入一批作业(10 到 70 个)。导入批次后,应用程序会指示登录用户“优先查找”那些新创建的作业。用户已经有一个他最喜欢的 locums 列表(1 到 20)。他想首先将工作分配给他最喜欢的人。这是通过ProcessJobBatch() 完成的。但是,有两种情况会阻止那里的流动:
- 如果某些工作不属于 有什么喜欢的地方吗?
- 如果整体中有一个 locum 怎么办 DB几乎可以做所有的工作,但 因为他不是最喜欢的?
所以,我最终得到了一个将工作与每个 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
【问题讨论】:
-
记住 backgroundWorker 在线程池中执行。你应该能够让一个踢另一个。所以理论上,你应该能够在另一个中运行一个,因为外部的 backgroundworker 正在订阅由内部触发的事件。总体而言,该解决方案听起来像是很多活动部件,但我可能无法正确理解您的伪代码。您能否解释一下为什么 ProcessJobBatch 的容量有限以及您如何确定何时需要处理 locum?
标签: c# .net linq backgroundworker