我想要实现的目标:
使用Parallel.For
(其他任何东西都可以,但发现这个是最简单的)我想增加一个名为max
的变量,使其达到100,000,000
,使用线程,但程序应该同时只使用X个线程。
代码片段:
using System;
using System.Threading;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace pool_threading
{
class MainClass
{
static int max=0;
static int current_max_thread=0;
public static void Main (string[] args)
{
Parallel.For(0, 100000000, new ParallelOptions { MaxDegreeOfParallelism = 50 },
i =>
{
max++;
if(Thread.CurrentThread.ManagedThreadId>current_max_thread)
current_max_thread=Thread.CurrentThread.ManagedThreadId;
});
Console.WriteLine ("I got to this number {0} using most {1} threads",max,current_max_tread);
}
public static void GetPage(int i)
{
}
}
}
结果:
我使用最多11个线程得到了这个数字38,786,886
现在。。。我不知道为什么我得到的数字38,786,886
小于38,786,886
,但我想这是因为多个线程试图在同一时间增加它,所以如果10个线程同时尝试,只有第一个线程会有机会。如果我错了,请纠正我。
最大的"问题"是,我一直得到11个线程,即使最大值设置为50(滚动代码查看最大值),如果我将其设置为最大值1个线程,我总是得到4(在这种情况下,可能4是最小值,但它仍然不能解释为什么我同时得到最大值只有11)。
这很简单,只需在循环中使用i
,而不是尝试增量和使用max
。你没有安全地增加它,但你没有理由尝试。Parallel.For
的整个点是它为您提供了循环索引,并确保每个循环索引只命中一次,不多也不少。
据我所知,这里有两件事:
首先,您正在从多个线程对max
进行深入研究。你可能有一台多核机器。这些行动可能相互重叠。要以线程安全的方式执行增量,您需要
Interlocked.Increment(ref max);
不是
max++; /* not thread safe */
其次,您并不总是得到MaxDegreeOfParallelism
中要求的线程数。你永远不会得到更多,但你可能会得到更少。
如果要使用并行性,请密切注意将在线程中运行的代码的线程安全性。
我认为您没有得到50个线程,主要有两个原因:
-
硬件。处理器可以用更少的线程做更多的事情,因为切换线程所需的时间不仅仅是更频繁地运行线程。这导致
-
托管代码。NET是一个托管代码系统。.Net的程序员知道以上内容,可能会设置一些限制和检查,以防止过多的线程运行。您在代码中设置的内容可能高于某个内部限制,因此它实际上被忽略了。此外,您正在设置一个最大值,因此Parallel.For()可以使用从1到X的任何线程数,无论它认为什么是最有效的。