首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多个任务会变慢

多个任务会变慢
EN

Stack Overflow用户
提问于 2011-09-13 04:56:08
回答 2查看 5.5K关注 0票数 18

代码:

代码语言:javascript
复制
static void DoIt(string name)
{
    Console.WriteLine("Hello {0} | {1}", name, Thread.CurrentThread.ManagedThreadID);
    Thread.Sleep(5000);
    Console.WriteLine("Bye {0} | {1}", name, Thread.CurrentThread.ManagedThreadID);
}

static void Main()
{
    Task.Factory.StartNew(() => DoIt("One"));
    Task.Factory.StartNew(() => DoIt("Two"));
    Task.Factory.StartNew(() => DoIt("Three"));
    Task.Factory.StartNew(() => DoIt("Four"));
    Task.Factory.StartNew(() => DoIt("Five"));
    Task.Factory.StartNew(() => DoIt("Six"));
    Task.Factory.StartNew(() => DoIt("Seven"));
    Task.Factory.StartNew(() => DoIt("Eight"));
    Task.Factory.StartNew(() => DoIt("Nine"));
    Task.Factory.StartNew(() => DoIt("Ten"));

    Console.ReadKey();
}

为什么它可以立即很好地启动前3个任务,但是任务4开始需要5-10秒,任务4开始后,任务5开始需要5-10秒,以此类推。是GC在做什么吗?有人能澄清一下发生了什么事吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-09-13 05:06:45

为什么它可以立即很好地启动前3个任务,但是任务4开始需要5-10秒,任务4开始后,任务5开始需要5-10秒,以此类推。是GC在做什么吗?有人能澄清一下发生了什么事吗?

默认情况下,第一次运行时,将使用最小数量的工作线程来分配ThreadPool。在调度完前4个任务后,线程池将随着时间的推移“加速”以处理更多任务,这就是您看到延迟的原因。

在我的系统(有8个内核)上,前8个是瞬时的,然后下两个会在一秒后启动。

在您的示例中,如果您运行测试两次,即second时间,那么所有线程都将立即启动。这是因为,在第一次运行之后,ThreadPool应该有足够的工作人员来立即安排这项工作。

尝试以下操作来查看此行为的实际效果。如果将SetMinThreads呼叫保留在适当位置,则所有这些都将立即安排。如果您注释掉它,您将看到,第一次,它需要一段时间,但第二次(假设您等待线程完成),线程将立即运行。

代码语言:javascript
复制
static void DoIt(string name)
{
    Console.WriteLine("Hello {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now);
    Thread.Sleep(5000);
    Console.WriteLine("Bye {0} | {1} - {2}", name, Thread.CurrentThread.ManagedThreadId, DateTime.Now);
}

static void Main()
{
    int workerThreads, complete;
    ThreadPool.GetMinThreads(out workerThreads, out complete);

    Console.WriteLine(workerThreads);

    // Comment out this line to see the difference...
    // WIth this commented out, the second iteration will be immediate
    ThreadPool.SetMinThreads(100, complete);

    Action run = () =>
        {
            for (int i = 0; i < 20; ++i)
            {
                int tmp = i;
                Task.Factory.StartNew(() => DoIt(tmp.ToString()));
            }
        };

    run();
    Console.WriteLine("Press a key to run again...");
    Console.ReadKey();

    run();

    Console.WriteLine("Press a key to exit...");
    Console.ReadKey();
}

请注意,这个行为实际上与第三方公共关系不大--它更多的是使用默认的TaskScheduler,它只是将任务传递给ThreadPool。例如,如果在StartNew()调用中使用LongRunning提示设置这些线程,它们都会立即启动(因为默认调度程序将设置一个新的专用线程并立即执行它)。

票数 18
EN

Stack Overflow用户

发布于 2011-09-13 05:04:20

TPL包含非常复杂的算法,可以适应工作负载。您正在经历的事情听起来很适合4核计算机-- TPL已经决定做一些它认为在创建了这么多线程的情况下是有益的事情。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7393938

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档