为什么我的并行 for 循环比 for 慢得多?
Why my parallel for loop is much slower than for?
我尝试用并行循环更改我的 for 循环,但速度太慢了,而不是在一分钟内完成循环,而是在 30 分钟内完成。循环所做的是从一个数字开始,检查它是奇数还是偶数。如果它是奇数,它乘以 3 并加 1。如果它是偶数,它除以 2。继续重复直到数字达到 4,并且有一个循环,每次重复 100 万次,数字增加 1。我提到的最后一个循环是我尝试更改为并行循环的循环。这是普通 for 循环的代码:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
for (int z = 0; z != 1000000; z++)
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
}
Console.WriteLine(" {0} times done", i * 1000000);
}
}
下面是并行代码:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
谁能帮我让它比普通的 for 循环更快,或者在这种情况下使用并行是愚蠢的,我应该只使用普通的 for 循环?如果我也将感谢任何帮助使正常的 for 循环更快。
Theodor Zoulias 指出性能不足的原因可能是因为它不是线程安全的。这可能会导致数字取任意值,并可能导致执行完全不同的计算。
要解决此问题,您需要使每个并行循环独立。据我所知,在您的示例中这很容易做到,因为您只需要确保所有修改的值都是本地的:
static void Main(string[] args)
{
BigInteger startvalue =new BigInteger(Math.Pow(2,68));
Console.WriteLine(startvalue );
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
var currentValue = startvalue + z;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
另一种可能是并行循环内的工作平均来说很小,导致线程开销很大。还有工作平衡的问题,Parallel.For 会在 'chunks' 做工作以减少线程开销,并尝试调整这些块的大小。如果工作量变化很大,这种适应可能会导致效率低下。
我尝试用并行循环更改我的 for 循环,但速度太慢了,而不是在一分钟内完成循环,而是在 30 分钟内完成。循环所做的是从一个数字开始,检查它是奇数还是偶数。如果它是奇数,它乘以 3 并加 1。如果它是偶数,它除以 2。继续重复直到数字达到 4,并且有一个循环,每次重复 100 万次,数字增加 1。我提到的最后一个循环是我尝试更改为并行循环的循环。这是普通 for 循环的代码:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
for (int z = 0; z != 1000000; z++)
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
}
Console.WriteLine(" {0} times done", i * 1000000);
}
}
下面是并行代码:
static void Main(string[] args)
{
BigInteger currenthighest =new BigInteger(Math.Pow(2,68));
BigInteger currentValue;
Console.WriteLine(currenthighest);
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
currentValue = currenthighest;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
currenthighest++;
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
谁能帮我让它比普通的 for 循环更快,或者在这种情况下使用并行是愚蠢的,我应该只使用普通的 for 循环?如果我也将感谢任何帮助使正常的 for 循环更快。
Theodor Zoulias 指出性能不足的原因可能是因为它不是线程安全的。这可能会导致数字取任意值,并可能导致执行完全不同的计算。
要解决此问题,您需要使每个并行循环独立。据我所知,在您的示例中这很容易做到,因为您只需要确保所有修改的值都是本地的:
static void Main(string[] args)
{
BigInteger startvalue =new BigInteger(Math.Pow(2,68));
Console.WriteLine(startvalue );
Console.ReadKey();
for (int i = 1; i > -1; i++)
{
Parallel.For(0, 1000000,z=>
{
var currentValue = startvalue + z;
while (currentValue != 4)
{
if (currentValue % 2 == 0)
{
currentValue = currentValue / 2;
}
else
{
currentValue = (currentValue * 3) + 1;
}
}
});
Console.WriteLine(" {0} times done", i * 1000000);
}
}
另一种可能是并行循环内的工作平均来说很小,导致线程开销很大。还有工作平衡的问题,Parallel.For 会在 'chunks' 做工作以减少线程开销,并尝试调整这些块的大小。如果工作量变化很大,这种适应可能会导致效率低下。