gpt4 book ai didi

c# - 奇怪的Powershell性能问题

转载 作者:行者123 更新时间:2023-12-03 01:24:11 27 4
gpt4 key购买 nike

注意:这是Euler项目Problem 14的解决方案。如果您仍然想自己解决问题,请不要继续阅读。

问题是要找到一百万以下的数字,作为Collatz sequence的起始数字,它会产生最长的此类序列。我的初始代码如下:

$r = @{}

for($i = 1; $i -lt 1000000; $i++) {
$n = 0
$a = $i
while ($a -gt 1) {
if ($r[$a]) {
$n += $r[$a]
break
}
if ($a % 2 -eq 0) {
$a /= 2
} else {
$a = $a * 3 + 1
}
$n++
}
$r[$i] = $n
}

$r.GetEnumerator() | sort Value | select -l 1 | %{$_.Key}

它尝试将哈希表用作已遇到的子序列的缓存,以节省时间。当我的计算机上该脚本的运行时间超过八分钟时,我感到非常惊讶。在C#中重新创建相同的代码:
using System;
using System.Collections.Generic;

class Problem14
{
public static void Main()
{
var ht = new Dictionary<long, int>();

for (int i = 1; i < 1000000; i++)
{
int count = 0;
long j = i;

while (j > 1)
{
if (ht.ContainsKey(j))
{
count += ht[j];
break;
}
if (j % 2 == 0)
j /= 2;
else
j = 3 * j + 1;

count++;
}
ht[i] = count;
}

KeyValuePair<long, int> max = new KeyValuePair<long, int>();
foreach (var n in ht)
{
if (n.Value > max.Value)
max = n;
}
Console.WriteLine(max.Key);
}
}

运行时间刚刚超过一秒钟。我知道执行速度并不是Powershell的主要目标。这是一种管理语言,对于这些任务,PS代码与cmdlet的比率可能与我在这里所做的非常不同。

不过,我不知道到底是什么原因导致了速度下降。

怀疑哈希表,我将其替换为用于数组的缓存。这导致在C#中执行时间约为200毫秒,在Powershell中约为32分钟。代码如下:
$r = ,0*1000000

for($i = 1; $i -lt 1000000; $i++) {
$n = 0
$a = $i
while ($a -gt 1) {
if ($r[$a]) {
$n += $r[$a]
break
}
if ($a % 2 -eq 0) {
$a /= 2
} else {
$a = $a * 3 + 1
}
$n++
}
if ($i -lt 1000000) {
$r[$i] = $n
}
}

$max = 0
for($i=1; $i -lt 1000000; $i++) {
if ($r[$i] > $r[$max]) {
$max = $i
}
}
$max


using System;

class Problem14
{
public static void Main()
{
var cache = new int[1000000];

for (int i = 1; i < 1000000; i++)
{
int count = 0;
long j = i;

while (j > 1)
{
if (j < 1000000 && cache[j] != 0)
{
count += cache[j];
break;
}
if (j % 2 == 0)
j /= 2;
else
j = 3 * j + 1;

count++;
}
cache[i] = count;
}

var max = 0;
for (int i = 1; i < cache.Length; i++)
{
if (cache[i] > cache[max])
max = i;
}

Console.WriteLine(max);
}
}

完全无缓存的变体在C#中大约为1.2秒。尚未在Powershell中尝试。

有任何想法吗?

最佳答案

首先,PowerShell是一种解释性语言(不固定,也不编译)。那总是很受伤。 ;-)

其次,您可以使用一些语言构造来避免多个解释步骤。例如,不要使用for(;;)语句,而要使用范围:

0..1000000 | foreach-object { foo $_ 

可能会有所帮助。

最重要的是,避免在循环中过度使用break和continue关键字-如果可能的话,请避免反转逻辑。在内部,这些关键字表示使用.NET异常的信号,因此是昂贵的操作。

希望这有助于您的理解。

编辑:这些关键字使用.NET异常信号

从System.Management.Automation.FlowControlNode.Execute(...):
switch (this._tokenId)
{
case TokenId.ExitToken:
{
int exitCode = this.GetExitCode(result);
throw new ExitException(base.NodeToken, exitCode);
}
case TokenId.ReturnToken:
throw new ReturnException(base.NodeToken, result);

case TokenId.BreakToken:
label = this.GetLabel(result, context);
throw new BreakException(base.NodeToken, label);

case TokenId.ContinueToken:
label = this.GetLabel(result, context);
throw new ContinueException(base.NodeToken, label);

-Oisin

关于c# - 奇怪的Powershell性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/819524/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com