我在powershell(v4)上有一个新手问题。
鉴于以下代码,
如果我改变功能DoNothing的内容来做某事,那么时间不会延长。
显然我在某个地方犯了一个大错,但我无法看到它的位置。非常感谢帮助我理解我的错误。
function DoNothing($val)
{
return $val
}
Write-Host "Script started..."
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
for($i=1
$i -le 100000
$i++){
#$t = $i
#$t = DoNothing($i)
$t = DoNothing $i
}
Write-Host "Script complete."
Write-Host "Total Elapsed Time: $($elapsed.Elapsed.ToString())"
答案 0 :(得分:2)
Good question. I believe this is just the performance overhead of making function calls in PowerShell, but I did some experimentation to check.
A few things I noticed:
1) Saving the file increased performance around 75% compared to just working out of the PowerShell ISE without saving the file (From 7.3 seconds to 4.3 seconds).
2) Turning DoNothing
into a parameterless function improved the execution time by an additional ~25% (From 4.3 seconds to 3.3 seconds). This would be useful if creating $i
as a global variable would save time, but I tested that as well and, sadly, it increased execution time to 4.7 seconds.
3) I thought maybe explicitly requesting $val
to be passed in as an int would decrease execution time, but it didn't. Time increased by about 0.2 seconds.
4) Naming the -val
parameter when calling DoNothing
($t = DoNothing -val $i
) did not improve performance.
5) Using $val
instead of return $val
did not improve performance.
6) Using -lt
instead of -le
did not improve performance.
7) Adding DoNothing
to a PS module with only the DoNothing
function in it severely decreased performance (from 4.3 seconds to 15 seconds).
So, I think this is all due to function overhead. I don't see anything 'wrong' in your code.
This has been an interesting experiment and might change when I choose to use PowerShell functions in the future. I wonder how this compares to other scripting languages.
Out of curiosity, I ran these same operations using C# and the whole thing completed in one one-thousandth of a second. Code is below.
class Program
{
private static int DoNothing(int val) {
return val;
}
static void Main(string[] args)
{
System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i <= 100000; i++)
{
int t = DoNothing(i);
}
Console.WriteLine(watch.Elapsed.ToString());
Console.ReadKey();
}
}
Now I've gone a bit further than this. I figure if you really needed this to be faster, maybe you could throw the workload out to C# from PowerShell. This ended up being MUCH MUCH FASTER than the initial implementation in PowerShell, but slower than the C# only option. This code runs in ~ 0.03 seconds. See the code below.
PowerShell (calling the C#)
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
Write-Host "Script started..."
$lib = [Reflection.Assembly]::LoadFile("C:\Users\you\source\ClassLibrary1\bin\Debug\ClassLibrary1.dll")
$type = $lib.GetType("ClassLibrary1.Class1")
$method = $type.GetMethod("MyFunction")
$o = [Activator]::CreateInstance($type)
$method.Invoke($o, $null)
Write-Host "Script complete."
Write-Host "Total Elapsed Time: $($elapsed.Elapsed.ToString())"
C# (doing the work)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary1
{
public class Class1
{
public static int DoNothing(int val)
{
return val;
}
public static void MyFunction()
{
for (int i = 1; i <= 100000; i++)
{
int t = DoNothing(i);
}
}
}
}
答案 1 :(得分:0)
有关信息,在Python中,同样的事情(使用函数DoNothing)需要0.01s。我不知道Python和Powershell函数处理之间的主要区别,但0.01s和11.5s的速度要快1k倍......
import datetime
def DoNothing(val):
return val
print("Script started...")
elapsed = datetime.datetime.now()
for i in range (1,100000):
#t = i
t = DoNothing(i)
print("Script complete.")
print('Total Elapsed Time: '+str(datetime.datetime.now() - elapsed))