我使用多个BackgroundWorker
控件以多线程方式运行某些任务。但是我发现当使用超过4个BackgroundWoker时,从第四个转发延迟超过第二个延迟到从拨打RunWorkerAsync
时实际执行。当使用多于4个时,线程不会立即运行BackgroundWorker
可以帮助我如何立即启动所有背景工作?
class TaskLog
{
public int task_id;
public DateTime call_time;
public DateTime start_time;
public DateTime end_time;
}
BackgroundWorker[] bws = new BackgroundWorker[18];
int[] tasks = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Queue<TaskLog> queueTask;
TaskLog[] records;
int task_complete = 999;
private void button1_Click(object sender, EventArgs e)
{
if (task_complete < tasks.Length) return;
task_complete = 0;
records = tasks.Select(t => new TaskLog { task_id = t }).ToArray();
queueTask = new Queue<TaskLog>(records);
for (int i = 0; i < bws.Length && queueTask.Count > 0; ++i)
{
bws[i] = new BackgroundWorker();
bws[i].DoWork += new DoWorkEventHandler(download_vid_work);
bws[i].RunWorkerCompleted += new RunWorkerCompletedEventHandler(download_vid_complete);
var x = queueTask.Dequeue();
x.call_time = DateTime.Now;
bws[i].RunWorkerAsync(x);
//Debug.WriteLine("start " + x.task_id);
}
}
void download_vid_work(object sender, DoWorkEventArgs e)
{
var record = (TaskLog)e.Argument;
record.start_time = DateTime.Now;
//Debug.WriteLine("actually start " + record.task_id);
Thread.Sleep(10000); // 10s
e.Result = record;
}
void download_vid_complete(object sender, RunWorkerCompletedEventArgs e)
{
var record = (TaskLog)e.Result;
record.end_time = DateTime.Now;
//Debug.WriteLine("complete " + item.ToString());
++task_complete;
if (task_complete == tasks.Length)
{
Debug.WriteLine("all tasks are completed!");
foreach (var r in records)
{
Debug.WriteLine("task {0} delay time: {1}", r.task_id, (r.start_time - r.call_time).TotalMilliseconds.ToString("0,0"));
}
}
else if (queueTask.Count > 0)
{
var bw = (BackgroundWorker)sender;
var nextTask = queueTask.Dequeue();
bw.RunWorkerAsync(nextTask);
nextTask.call_time = DateTime.Now;
}
}
下面是运行后的日志结果:
all tasks are completed!
task 1 delay time: 22
task 2 delay time: 24
task 3 delay time: 24
task 4 delay time: 23
task 5 delay time: 1,005
task 6 delay time: 2,002
task 7 delay time: 3,003
task 8 delay time: 4,003
task 9 delay time: 5,004
task 10 delay time: 6,005
您不能拥有无限数量的线程并期望它们全部运行。你可能有4个核心,他们都在处理一个线程,其他人不得不等待资源缺口才能运行。多线程的谬误之一就是添加大量的线程会使事情变得更快,通常它会让事情变得更慢! – Belogix 2015-03-19 10:55:14
@Belogix:Windows调度具有相同优先级循环的线程,最后我检查一个线程的量程大约为50ms。因此,尽管超过内核数量会使线程启动延迟一小段时间,但这不足以解释此处报告的一秒延迟。第五个线程必须等待最多50毫秒,然后才能使其中一个初始线程被抢占并允许第五个线程运行。 – 2015-03-19 12:12:54
微软在BackgroundWorker类中犯了一个设计错误,没有人在线程池线程理想的情况下使用它。但他们也很擅长修复他们的错误,您应该使用Task类来代替。您可以使用TaskCreationOptions.LongRunning选项来解决您的问题。请注意,您的代码非常虚假,您需要试用真实的代码。 – 2015-03-19 13:27:38