立即用4个以上的BackgroundWorker线程时无法运行 [英] Thread not run immediately when using more than 4 BackgroundWorker

查看:94
本文介绍了立即用4个以上的BackgroundWorker线程时无法运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用多个的BackgroundWorker 控制运行一些任务,多线程。但是,我发现,在使用超过4 BackgroundWoker,从4日的一个正向延迟超过第二个实际上是从致电时的RunWorkerAsync 执行。

能不能帮我,我怎么能立即启动所有的BackgroundWorker?

 类任务日志
{
    公众诠释TASK_ID;
    公众的DateTime call_time;
    公众的DateTime START_TIME;
    公众的DateTime END_TIME;
}

BackgroundWorker的[] BWS =新的BackgroundWorker [18];
INT []任务=新INT [] {1,2,3,4,5,6,7,8,9,10};
队列<任务日志> queueTask;
任务日志[]记录;
INT task_complete = 999;

私人无效的button1_Click(对象发件人,EventArgs的)
{
    如果(task_complete< tasks.Length)回报;

    task_complete = 0;

    记录= tasks.Select(T =>新建任务日志{TASK_ID = T})的ToArray()。
    queueTask =新问答其中,任务日志>(记录);

    对(INT I = 0; I&其中; bws.Length&安培;&安培; queueTask.Count大于0 ++ⅰ)
    {
        BWS [我] =新的BackgroundWorker();
        BWS [I] .DoWork + =新DoWorkEventHandler(download_vid_work);
        BWS [I] .RunWorkerCompleted + =新RunWorkerCompletedEventHandler(download_vid_complete);

        变种X = queueTask.Dequeue();
        x.call_time = DateTime.Now;

        BWS [I] .RunWorkerAsync(X);
        //Debug.WriteLine("start+ x.task_id);
    }
}

无效download_vid_work(对象发件人,DoWorkEventArgs E)
{
    VAR纪录=(任务日志)e.Argument;
    record.start_time = DateTime.Now;
    //Debug.WriteLine("actually启动+ record.task_id);

    Thread.sleep代码(10000); // 10S
    e.Result =记录;
}

无效download_vid_complete(对象发件人,RunWorkerCompletedEventArgs E)
{
    VAR纪录=(任务日志)e.Result;
    record.end_time = DateTime.Now;
    //Debug.WriteLine("complete+ item.ToString());

    ++ task_complete;
    如果(task_complete == tasks.Length)
    {
        的Debug.WriteLine(所有任务完成!);
        的foreach(在记录变种R)
        {
            的Debug.WriteLine(任务{0}延迟时间:{1},r.task_id,(r.start_time  -  r.call_time).TotalMilliseconds.ToString(0,0));
        }
    }
    否则如果(queueTask.Count大于0)
    {
        VAR体重=(BackgroundWorker的)发送;
        变种nextTask = queueTask.Dequeue();
        bw.RunWorkerAsync(nextTask);
        nextTask.call_time = DateTime.Now;
    }
}
 

下面是日志的结果运行后:

 所有的任务都完成了!
任务1延时时间:22
任务2的延迟时间:24
任务3延时时间:24
任务4延迟时间:23
任务5延时时间:1005
任务6延迟时间:2002
任务7延迟时间:3,003
任务8延时时间:4003
任务9延迟时间:5004
任务10延迟时间:6,005
 

解决方案

线程池类,它管理用于 BackgroundWorker的<线程池中的线程/ code>(和其他需求),不维护工人无限数量的线程可以运行。

您可以配置空闲线程(*)的实际数量,使用 ThreadPool.SetMinThreads()方法。正如你可以在你的情况看,当你开始启动你的程序,有四个空闲线程愿意接受工作的时候了。空转线程默认数量取决于各种相关的操作系统版本和配置的东西。

一旦有更多排队的工作项目线程池以外还有线程来服务他们来说,线程池类没有创建新的线程的时候了。它等待的时间很短的时间(你可以从你的测试,一秒看看),前提是它的可能的其他任务之一可能结束不久,这将是能够重复使用线程,而不是去创造另一个线程所有的麻烦(这将产生它自己的开销,甚至会减慢的线程已经运行的工作)。

在一般情况下,你应该避免覆盖默认值的线程池,因为它们一般都设置正确给您的操作系统版本,硬件等。例如,它不会帮助有比运行多个CPU绑定的主题你的机器上的CPU内核。让线程池类决定何时以及如何运行你的工作线程通常是最好的办法。


(*)以上是一个有点过于简单化。在新版本的.NET,线程的最小数目可能会或可能不会实际在任何特定时间存在。如果当有大于最小数目较少的工作项目进行排队,线程池将立即创建根据需要最多的最小新主题。除此之外,它然后转移到其更精细的创建和调度逻辑

I use multiple BackgroundWorker control to run some task as multithreading. But I found that when using more than 4 BackgroundWoker, the one from 4th forward delay more than second to actually execute from when calling RunWorkerAsync.

Could help me how can I start all backgroundworker immediately?

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;
    }
}

Here is log result after run:

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

解决方案

The ThreadPool class, which manages the thread pool threads used for BackgroundWorker (and other needs), does not maintain an infinite number of worker threads ready to run.

You can configure the actual number of idle threads (*), using the ThreadPool.SetMinThreads() method. As you can see in your case, when you initially start your program, there are four idle threads ready to accept work right away. The default number of idles threads depends on a variety of things related to the OS version and configuration.

Once there are more queued work items for the thread pool than there are threads to service them, the ThreadPool class does not create new threads right away. It waits for a short period of time (as you can see from your test, one second), on the assumption that it's possible one of the other tasks may finish soon and it will be able to reuse that thread rather than going to all the trouble of creating yet another thread (which incurs its own overhead and would even slow down the work of the threads already running).

In general, you should avoid overriding the default values for the thread pool, as they are generally set correctly given your OS version, hardware, etc. For example, it won't help to have more CPU-bound threads running than you have CPU cores on the machine. Letting the ThreadPool class decide when and how to run your worker threads is usually the best approach.


(*) The above is a bit of an over-simplification. In newer versions of .NET, the minimum number of threads may or may not actually exist at any given time. If work items are queued when there are fewer than the minimum number, ThreadPool will immediately create new threads as needed up to the minimum. Beyond that, it then shifts to its more elaborate creation and scheduling logic.

这篇关于立即用4个以上的BackgroundWorker线程时无法运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆