powershell - 调用自定义函数非常慢

标签 powershell

我有一个关于 powershell (v4) 的新手问题。

给定以下代码,

  • 当我在循环中执行 $t = $i 时需要 0.5 秒
  • 当我在循环中执行 $t = DoNothing($i) 时需要 11.5 秒
  • 当我在循环中执行 $t = DoNothing $i 时需要 11.5 秒

如果我改变函数 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())"

最佳答案

好问题。我相信这只是在 PowerShell 中进行函数调用的性能开销,但我做了一些实验来检查。

我注意到的一些事情:

1) 与仅在不保存文件的情况下使用 PowerShell ISE 相比,保存文件可将性能提高约 75%(从 7.3 秒增加到 4.3 秒)。

2)DoNothing 转换为无参数函数可将执行时间额外缩短约 25%(从 4.3 秒缩短至 3.3 秒)。如果将 $i 创建为全局变量可以节省时间,那么这将很有用,但我也对其进行了测试,遗憾的是,它将执行时间增加到 4.7 秒。

3) 我认为也许明确请求将 $val 作为 int 传递会减少执行时间,但事实并非如此。时间增加了大约 0.2 秒。

4) 在调用 DoNothing 时命名 -val 参数 ($t = DoNothing -val $i ) 没有提高性能。

5) 使用 $val 而不是 return $val 没有提高性能。

6) 使用 -lt 而不是 -le 并没有提高性能。

7)DoNothing 添加到只有 DoNothing 函数的 PS 模块会严重降低性能(从 4.3 秒到 15 秒) .

所以,我认为这都是由于函数开销造成的。我在您的代码中没有看到任何“错误”。

这是一个有趣的实验,当我将来选择使用 PowerShell 函数时可能会改变。我想知道这与其他脚本语言相比如何。

出于好奇,我使用 C# 运行了这些相同的操作,整个过程在千分之一秒内完成。代码如下。

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();
    }
}

现在我比这更进一步了。我认为如果您真的需要它更快,也许您可​​以将工作负载从 PowerShell 转移到 C#。这最终比 PowerShell 中的初始实现快得多,但比仅 C# 选项慢。 此代码运行时间约为 0.03 秒。请参阅下面的代码。

PowerShell(调用 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#(完成工作)

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);
            }
        }
    }
}

关于powershell - 调用自定义函数非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49199261/

相关文章:

Azure cmdlet : How to group Results with Invoke-AzCostManagementQuery?

unit-testing - 如何使用 Pester 模拟对 exe 文件的调用?

powershell - PowerShell Invoke-WebRequest,如何自动使用原始文件名?

powershell - 如何在PowerShell中遍历包含大量文件的文件夹?

命令中的 Powershell 对象字段

powershell - 使用 Powershell 解析 RSTCLI 的卷状态

powershell - 使用Powershell或批处理调用Graph API

powershell - 如何将 -Verbose 传播到模块函数?

powershell - 捕获 block 内未捕获异常的Powershell意外行为

Powershell - 登录/注销事件 - Get-WinEvent 与 Get-EventLog