【问题标题】:Unwanted delay between starting each BackgroundWorker array element启动每个 BackgroundWorker 数组元素之间的不必要延迟
【发布时间】:2016-05-08 08:55:44
【问题描述】:

我想创建一个 BackgroundWorkers 数组,它们彼此协同工作以利用多核处理器。假设我希望其中八个同时工作。我还想要一个单独的 Timer 线程在 GUI 中报告每个线程一直在处理的一些数据。

我的问题是这个。每个工人开始工作大约需要 3-4 秒。所以数组中的第一个工作元素立即开始。第二个在几秒钟后开始。第三个开始几秒钟后等等等等。

我希望他们都立即开始。我该如何解决这个问题?

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    BackgroundWorker[] bw;
    int threads = 8;
    data[] d;

    private void Form1_Load(object sender, EventArgs e)
    {
        d = new data[threads];
        for (int i = 0; i < threads; i++) d[i] = new data(i);

        bw = new BackgroundWorker[threads];
        for (int i = 0; i < threads; i++)
        {
            bw[i] = new BackgroundWorker();
            bw[i].DoWork += new DoWorkEventHandler(Work);
        }
        timer1.Enabled = true;
        for (int i = 0; i < threads; i++) bw[i].RunWorkerAsync(d[i]);
    }

    private void Work(object sender, DoWorkEventArgs e)
    {
        data o = (data)e.Argument;
        while (true) o.count += o.id;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {           
        StringBuilder sb = new StringBuilder();
        long total = 0;
        for (int n = 0; n < threads; n++) {
            sb.Append(d[n].id + ": " + d[n].count + "\n");
            total+=d[n].count;
        }
        sb.Append("TOTAL: "+total);
        richTextBox1.Text = sb.ToString();
    }



}

public class data {
    public int id;
    public long count;
    public data(int id)
    {
        this.id = id;
        this.count = 0;
    }
}

-------------------编辑:发现晚于 3-4 秒的延迟仅适用于您拥有的最大逻辑核心数。因此,如果您有 20 个内核,并设置 20 个线程,那很好。但是,如果您有 4 个内核并设置 20 个线程,则在创建前 4 个之后的 16 个线程之间会有延迟。

【问题讨论】:

    标签: c# multithreading parallel-processing backgroundworker


    【解决方案1】:

    我希望他们都立即开始。

    那么Backgroundworkers 不是正确的工具。甚至可能 Windows 也不是正确的操作系统。

    Backgroundworkers 在 ThreadPool 上运行,指导原则是仅将其用于短(

    简短的解决方案是增加 ThreadPool.Minthreads(查找实际名称/方法),但这仍然是一个古怪的解决方案。

    您没有提供足够的(真实)信息来获得更好的建议。

    【讨论】:

    • 哇,您的 ThreadPool.SetMinThreads 想法可行 - 谢谢!我担心的是,对于四核处理器和一个令人尴尬的并行问题,4 核应该几乎是 1 核的 4 倍。通常单核 10 秒的问题应该是四核大约 3 秒(非常粗略)。但是,如果每个线程需要 3 秒才能启动,那么问题可能需要大约 6-7 秒。换句话说,我希望所有核心尽快开始工作,而不是闲逛。如果他们在那里,那么他们应该准备好并愿意被使用。
    • 哦,补充一下,如果 BackgroundWorkers 用于
    • 当它们运行到几分钟时,0.5 秒的启动延迟应该无关紧要。但最好使用任务(使用 LongRunning 选项)或为此创建裸线程。
    • 这是 3 秒的启动延迟,而不是 0.5 秒顺便说一句(这将与每个连续的核心相乘)。因此,如果假设我采用 BackgroundWorker 路线,我是否会看到性能下降、内存使用量或其他问题?
    【解决方案2】:

    我想,while (true) o.count += o.id; 行消耗了太多 CPU,以至于其他操作可能会被阻塞。

    尝试在o.count += o.id; 之前添加Thread.Sleep(100); 或减少线程数(8 线程 + GUI 线程 => 9 线程仅适用于您的应用程序)。

    【讨论】:

    • 谢谢。现在我在每个新工人之间得到大约 0.5 秒。不理想,无论如何,我不想减慢主循环,因为我的程序(不是主 Q 中的这个短代码示例)需要性能。我尝试将线程数减少到 5 无济于事。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多