【问题标题】:why my threadpool 's threads do not finish at same time为什么我的线程池的线程不能同时完成
【发布时间】:2017-10-25 16:36:10
【问题描述】:

在主函数中,我写了这段代码:

            ThreadPool.SetMaxThreads(200, 200);

        for (int i = 0; i < 100; i++)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWhichWillCallSQL_test), i);
            Thread.Sleep(1);
        }

线程函数如下:

        static public void ThreadWhichWillCallSQL_test(Object o1)
    {
        Thread.Sleep(5000);
        Console.WriteLine(DateTime.Now.ToString()); 
        return;
    }

输出是:

    5/25/2017 2:00:01 PM
5/25/2017 2:00:01 PM
5/25/2017 2:00:01 PM
5/25/2017 2:00:01 PM
5/25/2017 2:00:02 PM
5/25/2017 2:00:03 PM
5/25/2017 2:00:04 PM
5/25/2017 2:00:05 PM
5/25/2017 2:00:05 PM
5/25/2017 2:00:06 PM
5/25/2017 2:00:06 PM
5/25/2017 2:00:06 PM
5/25/2017 2:00:06 PM
5/25/2017 2:00:07 PM
5/25/2017 2:00:07 PM
5/25/2017 2:00:08 PM
5/25/2017 2:00:08 PM
5/25/2017 2:00:09 PM
5/25/2017 2:00:09 PM
5/25/2017 2:00:10 PM
5/25/2017 2:00:10 PM
5/25/2017 2:00:10 PM
5/25/2017 2:00:11 PM
5/25/2017 2:00:11 PM
5/25/2017 2:00:11 PM
5/25/2017 2:00:11 PM
5/25/2017 2:00:12 PM
5/25/2017 2:00:12 PM
5/25/2017 2:00:12 PM
5/25/2017 2:00:13 PM
5/25/2017 2:00:13 PM
5/25/2017 2:00:13 PM
5/25/2017 2:00:14 PM
5/25/2017 2:00:14 PM
5/25/2017 2:00:14 PM
5/25/2017 2:00:15 PM
5/25/2017 2:00:15 PM
5/25/2017 2:00:15 PM
5/25/2017 2:00:15 PM
5/25/2017 2:00:16 PM
5/25/2017 2:00:16 PM
5/25/2017 2:00:16 PM
5/25/2017 2:00:16 PM
5/25/2017 2:00:17 PM
5/25/2017 2:00:17 PM
5/25/2017 2:00:17 PM
5/25/2017 2:00:17 PM
5/25/2017 2:00:18 PM
5/25/2017 2:00:18 PM
5/25/2017 2:00:18 PM
5/25/2017 2:00:18 PM
5/25/2017 2:00:19 PM
5/25/2017 2:00:19 PM
5/25/2017 2:00:19 PM
5/25/2017 2:00:19 PM
5/25/2017 2:00:20 PM
5/25/2017 2:00:20 PM
5/25/2017 2:00:20 PM
5/25/2017 2:00:20 PM
5/25/2017 2:00:20 PM
5/25/2017 2:00:21 PM
5/25/2017 2:00:21 PM
5/25/2017 2:00:21 PM
5/25/2017 2:00:21 PM
5/25/2017 2:00:22 PM
5/25/2017 2:00:22 PM
5/25/2017 2:00:22 PM
5/25/2017 2:00:22 PM
5/25/2017 2:00:22 PM
5/25/2017 2:00:23 PM
5/25/2017 2:00:23 PM
5/25/2017 2:00:23 PM
5/25/2017 2:00:23 PM
5/25/2017 2:00:23 PM
5/25/2017 2:00:24 PM
5/25/2017 2:00:24 PM
5/25/2017 2:00:24 PM
5/25/2017 2:00:24 PM
5/25/2017 2:00:24 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:25 PM
5/25/2017 2:00:26 PM
5/25/2017 2:00:26 PM
5/25/2017 2:00:26 PM
5/25/2017 2:00:26 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:27 PM
5/25/2017 2:00:28 PM
5/25/2017 2:00:28 PM
5/25/2017 2:00:28 PM
5/25/2017 2:00:28 PM
5/25/2017 2:00:28 PM

你可以注意到所有线程完成的整个过程持续了将近 28 秒,据我了解,这 100 个线程也许不能同时完成,但也不会有这么多时间不同。

我也设置了

ThreadPool.SetMaxThreads(200, 200);

并且只分配100个线程,所以不应该有任何线程等待其他人停止,对吧?

这里是完整代码

        using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;

    namespace ThreadpoolDelay
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    ThreadPool.SetMaxThreads(200, 200);

                    for (int i = 0; i < 30; i++)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadWhichWillCallSQL_test), i);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }

                Console.WriteLine("\nPress ENTER to continue...");
                Console.Read();
            }
            public static void ThreadWhichWillCallSQL_test(Object o1)
            {
                Thread.Sleep(5000);
                Console.WriteLine(DateTime.Now.ToString());
                return;
            }

        }
    }

【问题讨论】:

  • 我的环境是 Visual Studio 2012 和 .net FrameWork 4.5
  • 如果没有可靠地重现问题的良好minimal reproducible example,只能猜测,不能回答。但是,SetMaxThreads() 不会向线程池添加新的活动线程。它只是设置可能的最大值。因此,您仍然必须等待线程池填充更多线程,因为您现有的工作项花费的时间太长。如果你运行两次测试会发生什么?它是否像您期望的第二次那样工作? 为什么你甚至在乎?你真的有一台 100 核的机器吗?
  • 嗨,我没有100核的机器,但是我的机器可以运行30个线程我想,当我用30个线程测试时,最早和最晚的线程完成时间仍然有11秒的不同,我已将完整代码添加到这篇文章中
  • 正如https://stackoverflow.com/questions/7600774/threadpool-not-starting-new-thread-instantly 的问题/答案所指出的,您看错了方向。这并不是说他们没有同时结束。这是线程池需要时间来向池中添加更多线程。所以他们不会都开始在同一个(ish)时间。

标签: c# multithreading threadpool thread-sleep queueuserworkitem


【解决方案1】:

在您的示例中,线程没有同时启动。在 SetMaxThreads

之后添加以下调用
ThreadPool.SetMinThreads(200, 200);

这将使线程同时启动。这是关于 ThreadPool 线程创建机制的东西。我建议阅读ThreadPool documentation了解详情。

要更正确地调试它,请更新您的 ThreadWhichWillCallSQL_test 方法以添加开始时间:

    static void ThreadWhichWillCallSQL_test(object o1)
    {
        Console.WriteLine("start:"  + DateTime.Now);
        Thread.Sleep(5000);
        Console.WriteLine("finish: " + DateTime.Now);
    }

【讨论】:

  • 太棒了,它有效。是的,我并没有真正仔细阅读文档,只是复制并结合了其他人的代码。谢谢。
【解决方案2】:

好问题。

线程拉取中线程的执行取决于许多因素,其中一个因素是 cpu core 。它让线程在每个内核中运行,一旦完成,它就会放置另一个。

示例:如果有 4 个核心 cpu。它同时并行放置 4 个线程,然后将下一个线程作为线程完成它们的任务。机制有点像,不完全是。 你也放了5秒延迟(线程睡眠)所以 计算就像如果有 4 核:(30 线程/4 核)*5 有些类似,不完全是。

您也可以在那里查看更多信息:https://msdn.microsoft.com/en-us/library/3dasc8as(v=vs.80).aspx

【讨论】:

  • 并非如此。池如何分配线程是一个实现细节,对于不同的版本可能会有很大的不同。然而,它不会为每个内核分配一个线程。
  • 同意 adrino 但将多线程分配给核心并在它们之间切换上下文
  • 上下文切换?是的当然。如果池为每个请求分配一个线程,则总执行时间约为 5 秒(忽略任何开销)。每个核心一个?它分配更多的线程,在需要时根据复杂策略创建新线程,直到最大 OP 集。短寿命操作的完美行为。当然,使用池分配 30 个长延迟会利用这个问题,但这只是人为的。
  • 当一个线程休眠时,许多其他线程使用同一个内核(这是在亲和力之间的权衡,有利于缓存,保持所有内核繁忙,有利于并行)
  • 感谢 Adriano Repetti 的精彩解释
猜你喜欢
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多