核心与我可以生成的线程数之间的关系

发布于 2024-07-29 23:48:36 字数 234 浏览 10 评论 0原文

我有一个英特尔四核 CPU。

如果我要开发一个仅在我的机器上使用的 Winforms 应用程序(顺便说一句,我使用 C#),我可以生成多少个线程?

内核与我可以同时运行的最大线程数之间是否存在某种相关性? 我是否需要查明有多少线程正在运行,如果是这样,这可能吗? (我知道有诸如最小和最大线程之类的属性)? 这是否取决于线程池(该池中的最大线程数是否会改变?)。 这是这篇文章/线程的 C# 部分。

I have a Intel Quad Core CPU.

If I was to develop a Winforms application which only be used on my machine (I use C# btw), how many threads can I spawn?

Is there some sort of correlation between cores and the max number of threads I can have running at any one time? Would I need to find out how many threads are running at any one time and if so, is this possible? (I know there's properties like min and max threads)? Would this depend on the threadpool (does the max no of threads in this pool change?). This is the C# part of this post/thread.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

香草可樂 2024-08-05 23:48:36

必须衡量。 也就是说,对于 N 个核心,我通常通过在 N+12N 线程之间生成来获得最佳结果。 但你必须衡量。

You have to measure. That said, with N cores I usually get the best results by spawning between N+1 and 2N threads. But you have to measure.

懒猫 2024-08-05 23:48:36

这一切都取决于,如果您的线程在 100% 的时间内处于活动状态(并且不等待 IO),那么每个 CPU 拥有超过 1 个线程就没有什么意义。 然而,这种情况很少发生,除非您正在执行复杂的数值计算。

.Nets线程池有: http://msdn.microsoft.com/ en-us/library/system.threading.threadpool.aspx

线程池的默认大小为
每个可用工作线程 250 个
处理器和 1000 个 I/O 完成
线程。

所以,我想说,除了:

  • 测量测量测量之外,任何人都可以给你很少的建议。

在某些时候,当您添加更多线程时,由于上下文切换和同步,事情会变得更慢

It all depends, if your threads are active (and not waiting for IO) 100% of the time then there is little point in having more that 1 thread per CPU. However, this is rarely the case unless you are performing complex numeric calculations.

.Nets threadpool has: http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx

The thread pool has a default size of
250 worker threads per available
processor, and 1000 I/O completion
threads.

So, I would say, there is very little recommendations anyone can give you, besides:

  • Measure measure measure.

At some point when you add more threads stuff will get slower, due to context switching and synchronization.

烏雲後面有陽光 2024-08-05 23:48:36

虽然线程和内核之间存在松散的相关性(线程真正并发执行的唯一方法是它们在单独的内核上运行,但这种知识的价值比您想象的要低),但真正的工作是由操作系统调度程序,在本例中为 Windows 中的线程调度程序。

至于可以创建多少个线程,这会因系统而异。 ThreadPool 类对生成您自己的线程没有任何限制; 它有一个在内部管理自己的线程池。 这些是您在检查 ThreadPool 类的属性时可以看到的值。 然而,这并不是说您应该生成无限的线程;而是说您应该生成无限的线程。 最终,操作系统在线程之间切换所花费的时间将多于实际允许线程运行所花费的时间。 通过基准测试找出适合您的应用程序的线程数。

你到底想做什么?

While there is a loose correlation between threads and cores (the only way for threads to execute truly concurrently would be for them to run on separate cores, but that knowledge is of less value than you might think), the real work is done by the operating system scheduler, in this case the thread scheduler in Windows.

As to how many threads you can create, that will vary from system to system. The ThreadPool class does not place any restrictions on spawning your own threads; it has a, well, pool of threads that it manages itself internally. Those are the values you can see when inspecting the properties of the ThreadPool class. That is not to say, however, that you should spawn limitless threads; eventually the OS will be spending more time switching between your threads than it will spend actually allowing your threads to run. Figure out how many threads are appropriate for your application through benchmarking.

What exactly are you trying to do?

奶气 2024-08-05 23:48:36

我可以生成多少个线程?

哇,比您想要的最佳吞吐量要多得多(数百或数千倍)。

我知道的每线程限制(在 Windows 上)是:

  • 16 位线程 ID
  • 用户空间堆栈的 4-8KB 分配(通常更多)
  • 不可分页的内核空间上下文和堆栈,例如 16KB

Dotnet可能会为其自己的东西增加一堆每个线程的开销。 GC等。

我喜欢用于 WAG 的一个公式是:

threads = 2 * (cpu cores + active disk spindles)

最佳数字通常在其两倍之内。 的。 理论上,所需的线程与 CPU 核心成正比(出于明显的原因),但某些线程会在磁盘 I/O 上阻塞。 乘以 2 可以让 CPU 在其他线程被阻塞时有事可做。

不管怎样,从那开始并测量它。 工作线程的数量是整个问题中最容易稍后调整的部分,所以现在不要太担心。

how many threads can I spawn?

Waaay, waaay more (hundreds or thousands of times) than you would want to spawn for optimal throughput.

The per-thread limitations (on Windows) I'm aware of are:

  • 16-bit thread ID
  • 4-8KB allocation for user-space stack (typically, much more)
  • Non-pageable kernel-space context and stack, something like 16KB

Dotnet probably adds a bunch of per-thread overhead for its own stuff. GC and the like.

One formula I like use for a WAG is:

threads = 2 * (cpu cores + active disk spindles)

The optimal number is usually within a factor of two of that. of that. The theory is that needed threads are proprotional to cpu cores (for obvious reasons), but also that some threads will block on disk I/O. Multiplying by two gives the CPU something to do while other threads are blocked.

Anyway, start with that and measure it. The number of worker threads is the easiest part of the whole problem to adjust later, so don't worry about it too much now.

戏剧牡丹亭 2024-08-05 23:48:36

只是想知道启动多个线程首先会达到什么限制。 我编写了以下简单的测试程序并尝试了它。 现在我认为内存是限制因素。 我能够运行 1000 个线程,但如果没有 Thread.Sleep() 系统会变得“有点反应迟钝”。 对于 2000 个线程,在启动大约 1800 个线程后,我遇到了内存不足异常。 (配备 Intel Core 2 Duo T5800 2.0 GHz、3.0 GiB RAM 的笔记本电脑,以及在带有 .NET Framework 3.5 SP1 的 WIndows XP SP3 上运行的“少数”应用程序)

更新

内存不足异常是由线程的堆栈。 在线程构造函数上指定堆栈大小后(我使用了 64 kB,但可能得到了我目前不知道的最小大小),我能够启动 3500 个线程(使用 Thread.Sleep() ) )。

using System;
using System.Linq;
using System.Threading;

namespace GeneralTestApplication
{
    class Program
    {
        private static void Main()
        {
            Console.WriteLine("Enter the number of threads to start.");

            while (!Int32.TryParse(Console.ReadLine(), out Program.numberThreads)) { }

            Program.counters = new Int64[Program.numberThreads];

            Console.WriteLine("Starting {0} threads.", Program.numberThreads);

            for (Int32 threadNumber = 0; threadNumber < Program.numberThreads; threadNumber++)
            {
                new Thread(Program.ThreadMethod).Start(threadNumber);
            }

            Console.WriteLine("Press enter to perform work on all threads.");
            Console.ReadLine();

            Program.manualResetEvent.Set();

            Console.WriteLine("Press enter to stop all threads.");
            Console.ReadLine();

            Program.stop = true;

            Console.WriteLine("At least {0} threads ran.", Program.counters.Count(c => c > 0));

            Console.ReadLine();
        }

        private static Int32 numberThreads = 0;
        private static Int64[] counters = null;
        private static readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);
        private static volatile Boolean stop = false;

        public static void ThreadMethod(Object argument)
        {
            Int32 threadNumber = (Int32)argument;

            Program.manualResetEvent.WaitOne();

            while (!Program.stop)
            {
                Program.counters[threadNumber]++;

                // Uncomment to simulate heavy work.
                Thread.Sleep(10);
            }
        }
    }
}

Just wondered what limit would be hit first by starting many threads. I wrote the following simple test program and tried it. Now I assume that memory is the limiting factor. I was able to run 1000 threads, but without the Thread.Sleep() the system became "a bit inresponsive". With 2000 threads I got an out of memory exception after starting around 1800 threads. (Notebook with a Intel Core 2 Duo T5800 2.0 GHz, 3.0 GiB RAM and a "few" applications running on WIndows XP SP3 with .NET Framework 3.5 SP1)

UPDATE

The out of memory exception is caused by the stack of the threads. After specifying the stack size on the thread constructor (I used 64 kB but got probably the minimum size I don't know at the moment) I was able to start 3500 threads (with Thread.Sleep()).

using System;
using System.Linq;
using System.Threading;

namespace GeneralTestApplication
{
    class Program
    {
        private static void Main()
        {
            Console.WriteLine("Enter the number of threads to start.");

            while (!Int32.TryParse(Console.ReadLine(), out Program.numberThreads)) { }

            Program.counters = new Int64[Program.numberThreads];

            Console.WriteLine("Starting {0} threads.", Program.numberThreads);

            for (Int32 threadNumber = 0; threadNumber < Program.numberThreads; threadNumber++)
            {
                new Thread(Program.ThreadMethod).Start(threadNumber);
            }

            Console.WriteLine("Press enter to perform work on all threads.");
            Console.ReadLine();

            Program.manualResetEvent.Set();

            Console.WriteLine("Press enter to stop all threads.");
            Console.ReadLine();

            Program.stop = true;

            Console.WriteLine("At least {0} threads ran.", Program.counters.Count(c => c > 0));

            Console.ReadLine();
        }

        private static Int32 numberThreads = 0;
        private static Int64[] counters = null;
        private static readonly ManualResetEvent manualResetEvent = new ManualResetEvent(false);
        private static volatile Boolean stop = false;

        public static void ThreadMethod(Object argument)
        {
            Int32 threadNumber = (Int32)argument;

            Program.manualResetEvent.WaitOne();

            while (!Program.stop)
            {
                Program.counters[threadNumber]++;

                // Uncomment to simulate heavy work.
                Thread.Sleep(10);
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文