gpt4 book ai didi

powershell - 基于 Action 的对象事件有时会丢失

转载 作者:行者123 更新时间:2023-12-02 22:48:08 27 4
gpt4 key购买 nike

假设某个 PS 代码中引用的对象已知在 Register-ObjectEventUnregister-Event 之间触发了 100 个事件。期望主机代码接收 100 个事件。但是,它有时会收到不到 100 个,通常会少很多。

我看到这种情况一直发生在 Windows 7 的 PS v3、v4 和 v5.1 中。 下面发布的简单测试用例似乎在 Windows 10 下工作,但在 Windows 7 中的失败让我怀疑整个方法是否存在根本性错误。

[ 编辑 ] 在 Windows 10 和 PS v5.1 中也会发生同样的情况,只是比在 Windows 7 中要少。$fired = 10000 需要运行几千次> 让它发生,但它最终发生了。 [结束编辑]

实现它的最小独立代码(无耻地改编自一个答案 here ):

$src = @'
using System;

namespace Utils {
public static class StaticEventTest
{
public static event EventHandler Fired;

public static void RaiseFired()
{
if (Fired != null)
{
Fired(typeof(StaticEventTest), EventArgs.Empty);
}
}
}}
'@

Add-Type -TypeDefinition $src

$fired = 1000
$global:recvd = 0

$srcId = 'Fired'

$id = Register-ObjectEvent ([Utils.StaticEventTest]) Fired `
-SourceIdentifier $srcId -Action { $global:recvd++ }

for ($i = 1; $i -le $fired; $i++) {
[Utils.StaticEventTest]::RaiseFired()
}

Unregister-Event -SourceIdentifier $srcId
Receive-Job -Job $id -Wait -AutoRemoveJob

if ($fired -eq $global:recvd) {
("total {0} events" -f $fired)
} else {
("total {0} events fired - {1} received" -f $fired, $global:recvd)
}

将上面的内容保存为 test.ps1 并在循环中运行会得到如下结果(在 Windows 7 上):

C:\etc>for /l %n in (1, 1, 10) do @powershell.exe  -executionPolicy remoteSigned -file test.ps1
total 1000 events
total 1000 events
total 1000 events
total 1000 events fired - 391 received
total 1000 events
total 1000 events
total 1000 events fired - 59 received
total 1000 events
total 1000 events fired - 199 received
total 1000 events

非常感谢任何见解。

最佳答案

您正在“丢失”事件,因为您过早结束脚本。 Register-ObjectEvent ([Utils.StaticEventTest]) Fired -SourceIdentifier $srcId -Action { $global:recvd++ } 定义的事件操作将与您的脚本异步执行。如果我重复你所做的,我会得到更糟糕的结果(可能是由于虚拟环境):

C:\Users\user\Desktop>for /l %n in (1, 1, 10) do @powershell.exe  -executionPolicy remoteSigned -file test.ps1
total 1000 events fired - 17 received
total 1000 events fired - 100 received
total 1000 events fired - 202 received
total 1000 events fired - 16 received
total 1000 events fired - 3 received
total 1000 events fired - 120 received
total 1000 events fired - 1 received
total 1000 events fired - 162 received
total 1000 events fired - 1 received
total 1000 events fired - 27 received

但是当我在 for 循环之后添加 Start-Sleep -Seconds 5 时,我得到了这个结果(至少在我的环境中):

C:\Users\user\Desktop>for /l %n in (1, 1, 10) do @powershell.exe  -executionPolicy remoteSigned -file test.ps1
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events
total 1000 events

所以你触发的所有事件都在那里,没有事件丢失。但是,如果您想在解雇它们后立即查看对它们执行的操作,则必须等到所有(异步)操作都已执行。

当然,固定时间跨度的Start-Sleep在这里不是一个选项,因为你无法知道系统执行所有 Action 需要多长时间。但它显示了原因,为什么你认为你正在失去事件。

一种可能的等待事件的方法是在 for 循环之后的这一行:

while ($global:recvd -lt $fired) {Start-Sleep -Milliseconds 10}

这甚至适用于每次迭代 100.000 个事件(真正尝试过):

C:\Users\user\Desktop>for /l %n in (1, 1, 10) do @powershell.exe  -executionPolicy remoteSigned -file test.ps1
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events
total 100000 events

没有一个事件丢失。这让我相信事件的触发和监听会按预期工作。我无法复制任何反证据。

关于powershell - 基于 Action 的对象事件有时会丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61264838/

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