Benutzer mit den meisten Antworten
Object-Array 'Object[]' richtig verwenden

Frage
-
Hallo Forum!
ich habe ein Problem bei der Speicherung von Objekten vom Typ System.IO.Ports.SerialPort in einem Object-Array, wenn ich diesen mit 'Add-Member' Properties hinzufüget habe. Ich zeige hier mal was ich meine:
Function OpenComPorts-ForGrblConnection { param ( [ValidateSet(300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600)] [Int] $Baudrate = 115200, [ValidateSet(7, 8)] [Int] $DataBits = 8, [ValidateSet('Even', 'Mark', 'None', 'Odd', 'Space')] [String] $Parity = 'None', [ValidateSet('None', 'One', 'OnePointFive', 'Two')] [String] $StopBits = 'One' ) $PortNames = [System.IO.Ports.SerialPort]::GetPortNames() $A = New-Object 'Object[]' $PortNames.Count For ($i=0; $i -le $PortNames.Count - 1; $i++) { $c = New-Object -TypeName System.IO.Ports.SerialPort $Port,$Baudrate,$Parity,$Databits,$StopBits #$A[$i] = $c $c.PortName = $PortNames[$i] $c.Open() If ($c.IsOpen) { $c.WriteLine('$I') $Response = $c.ReadExisting() $Response = $Response -split "\r\n" If ($Response[1] -eq "ok") { Add-Member -InputObject $c -MemberType NoteProperty -Name "GrblOk" -Value $true #-TypeName Bool If ($Response[0] -match "\d{8}") { $BuildDate = [System.DateTime]::ParseExact($Matches[0],"yyyyMMdd", $null) Add-Member -InputObject $c -MemberType NoteProperty -Name "BuildDate" -Value $BuildDate #-TypeName DateTime If ($Response[0] -match "\d{1}\.\d{1}[a-z]{1}") { Add-Member -InputObject $c -MemberType NoteProperty -Name "BuildVersion" -Value ($Matches[0]) #-TypeName String $A[$i] = $c } } } else { $c.Close() } } } Return $A }
Okay - der Code lässt sich nur sinnvoll mit entsprechender Hardware am Comport betreiben, aber das Prinzip sollte klar sein. Es werden nacheinander alle Comports geöffnet und bei der Kommunikation bestimmte Antworten erwartet. Add-Member fügt entsprechend NoteProperties zu den Serial-Objekten hinzu. Die Objektereferenz befinden sich zu dem Zeitpunkt noch nicht im Array, aber wenn ich die Zuweisung '$A[$i] = $c' mache gerät alles durcheinander.
Vermutlich mache ich mit dem Array etwas Grundsätzliches falsch. Hat jemand die Checkung :-)
Michael L.
Antworten
-
Hallo,
das mit der festen Groesse habe ich irgendwie ueberlesen, es sollte aber auch gehen, das Array $a leer ohne feste Groesse zu definieren und dann im IF Zweig
$a += $c
Beste Groesse
brima- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 14. September 2016 14:48
-
> Das passt.
Ja, aber... ;) Man sollte dazu wissen, das beim hinzufügen mit "+=" Powershell im Speicher jedesmal zuerst ein komplett neues Array mit allen Elementen des alten Arrays + dem jeweils neu hinzugefügten Element erzeugt und dann erst das alte Array überschreibt. Das liegt daran, das Arrays per Definition Elementgruppen mit fest definierter Größe sind.
Diese Methode ist bei 5-10 Elementen egal, bei Hunderten und mehr, sehr, sehr langsam. Unter Umständen kann sogar der Speicher zum Problem werden.
Lösung: Eine dynamische Liste statt dessen nehmen.
$meinArray = New-Object System.Collections.Generic.List[System.Object]
$meinArray.add($meinElement) oder
$meinArray.add("Test")
Neben einer nun sehr effizenten add()-Methode kannst du damit sogar Elemente wieder entfernen, mit remove().
Grüße, Denniver
Blog: http://bytecookie.wordpress.com
Neu: Powershell Code Manager v5 ! Link
(Schneller, besser + komfortabler scripten.)
Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
Warum das Ganze? Hier gibts die Antwort.- Bearbeitet Denniver ReiningMVP, Moderator Montag, 12. September 2016 13:06
- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 14. September 2016 14:48
Alle Antworten
-
Hallo brima,
hab jetzt noch ein wenig rumprobiert. Mit '+=' geht es nicht, da dass Array eine feste Größe hat. Wenn ich aber auch die sonst leer gelassenen Array-Elemente mit den unbenutzten Com-Ports befülle, klapts.
} else { $c.Close() $A[$i] = $c }
Vielen Dank dennoch!
Michael L.
-
Hallo,
das mit der festen Groesse habe ich irgendwie ueberlesen, es sollte aber auch gehen, das Array $a leer ohne feste Groesse zu definieren und dann im IF Zweig
$a += $c
Beste Groesse
brima- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 14. September 2016 14:48
-
Feste Größe is doch sowieso des Teufels ;-) Zumal Du sie eh zur Laufzeit ermittelst, indem Du die Ports ausliest...
Evgenij Smirnov
msg services ag, Berlin -> http://www.msg-services.de
my personal blog (mostly German) -> http://it-pro-berlin.de
Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.comIn theory, there is no difference between theory and practice. In practice, there is.
-
> Das passt.
Ja, aber... ;) Man sollte dazu wissen, das beim hinzufügen mit "+=" Powershell im Speicher jedesmal zuerst ein komplett neues Array mit allen Elementen des alten Arrays + dem jeweils neu hinzugefügten Element erzeugt und dann erst das alte Array überschreibt. Das liegt daran, das Arrays per Definition Elementgruppen mit fest definierter Größe sind.
Diese Methode ist bei 5-10 Elementen egal, bei Hunderten und mehr, sehr, sehr langsam. Unter Umständen kann sogar der Speicher zum Problem werden.
Lösung: Eine dynamische Liste statt dessen nehmen.
$meinArray = New-Object System.Collections.Generic.List[System.Object]
$meinArray.add($meinElement) oder
$meinArray.add("Test")
Neben einer nun sehr effizenten add()-Methode kannst du damit sogar Elemente wieder entfernen, mit remove().
Grüße, Denniver
Blog: http://bytecookie.wordpress.com
Neu: Powershell Code Manager v5 ! Link
(Schneller, besser + komfortabler scripten.)
Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
Warum das Ganze? Hier gibts die Antwort.- Bearbeitet Denniver ReiningMVP, Moderator Montag, 12. September 2016 13:06
- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 14. September 2016 14:48
-
Hallo,
zur Anmerkung von Denniver hier zwei Beispiele um die Laufzeit zu vergleichen.
# Array Measure-Command { $Array = @() $i = 0 do { $Array += "$i" $i++ } until ($i -gt 100000) } # ArrayList Measure-Command { $ArrayList = New-Object System.Collections.ArrayList $i = 0 do { $Null = $ArrayList.Add("$i") $i++ } until ($i -gt 100000) }
Beste Gruesse
brima -
Ja super - ist schon beeindruckend. Hab mir mal die Mühe gemacht, das grafisch darzustellen.
Dazu habe ich Excel und folgenden Code benutzt:
$NumElements = 32000 $ResultList = New-Object System.Collections.ArrayList # Array $i = 0 $Array = @() do { $ResultElement = New-Object -TypeName Object Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Index -Value 0 Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Statically -Value 0 Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Dynamically -Value 0 Add-Member -InputObject $ResultElement -MemberType NoteProperty -Name Factor -Value 0 $s = (Measure-Command {$Array += "$i"}).TotalMilliseconds $ResultList.Add($ResultElement) $ResultElement.Index = $i $ResultElement.Statically = $s $i++ } until ($i -gt $NumElements) # ArrayList $i = 0 $ArrayList = New-Object System.Collections.ArrayList do { $d = (Measure-Command {$Null = $ArrayList.Add("$i")}).TotalMilliseconds $ResultList[$i].Dynamically = $d $ResultList[$i].Factor = $ResultList[$i].Statically / $ResultList[$i].Dynamically $i++ } until ($i -gt $NumElements) $ResultList | Export-Csv -Path D:\Temp\ArrayMeasureCompare.csv -NoClobber -NoTypeInformation -Encoding ASCII -Delimiter ";"
Michael L.