AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein TGUID - einzigartige ID auf andere Computer Systeme ?
Thema durchsuchen
Ansicht
Themen-Optionen

TGUID - einzigartige ID auf andere Computer Systeme ?

Ein Thema von paule32.jk · begonnen am 20. Okt 2023 · letzter Beitrag vom 2. Nov 2023
Antwort Antwort
Seite 4 von 7   « Erste     234 56     Letzte »    
Benutzerbild von paule32.jk
paule32.jk

Registriert seit: 24. Sep 2022
Ort: Planet Erde
218 Beiträge
 
Delphi 11 Alexandria
 
#31

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 10:05
okay, war ne doofe Frage ...
hätte ich auch gleich drauf kommen können ...
siehe Anhang (Bild) ...
Miniaturansicht angehängter Grafiken
bigdate.jpg  
Frag doch einfach
Alles was nicht programmiert werden kann, wird gelötet
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.336 Beiträge
 
Delphi 11 Alexandria
 
#32

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 13:58
Vielen Dank für die Infos und Hilfen!


Ich habe mir mal angehen, wie TSystemTime realisiert ist.
Nur mal eine kurze Übersicht, falls es jemanden direkt interessiert:
Delphi-Quellcode:
  PSystemTime = ^TSystemTime;
  _SYSTEMTIME = record
    wYear: Word;
    wMonth: Word;
    wDayOfWeek: Word;
    wDay: Word;
    wHour: Word;
    wMinute: Word;
    wSecond: Word;
    wMilliseconds: Word;
  end;
  {$EXTERNALSYM _SYSTEMTIME}
  TSystemTime = _SYSTEMTIME;
  SYSTEMTIME = _SYSTEMTIME;
  {$EXTERNALSYM SYSTEMTIME}
Das braucht natürlich einiges an Speicherplatz. Ich habe mich jetzt für GetTickCount entschieden, das die Systemlaufzeit als Cardinalwert zurück liefert.

Als Korrektur will ich die neue Unit nochmal hier einbinden. Vielleich hilf es ja mal jemandem.

Delphi-Quellcode:
unit myGuid;

interface

  uses

    System.Classes;

  type

    PmyGUID = ^TmyGUID;

    TmyGUID = record //: 12 Byte / 96 Bit
      C : Cardinal; //: 4 Byte / 32 Bit
      TS1: Cardinal; //: 4 Byte / 32 Bit
      TS2: Cardinal; //: 4 Byte / 32 Bit
      class function Create(const aGuid: PmyGUID): TmyGUID; overload; static;
      class function Create(const aGuid: String): TmyGUID; overload; static;
      class function Create(const aGuid: TmyGUID): TmyGUID; overload; static;
      class function CreateEmpty: TmyGUID; static;
      class function CreateNew: TmyGUID; static;
      class function StringIsValidGuid(const aGuid: String): Boolean; static;
      class operator Equal(const Left, Right: TmyGUID): Boolean;
      class operator NotEqual(const Left, Right: TmyGUID): Boolean; inline;
      function GetHashCode: Integer;
      function IsEmpty: Boolean;
      function ToString: String;
      procedure DoEmpty;
      procedure DoNew;
      procedure FromString(const aGuid: String);
      procedure ReadFromStream(const aStream: TMemoryStream);
      procedure WriteToStream(const aStream: TMemoryStream);
    end;

implementation

  uses

    System.SysUtils, System.Hash, Winapi.Windows;

  const

    MaxCardinal = 4294967295;

  var

    customTS1: Cardinal = 0;
    customTS2: Cardinal = 0;
    customC : Cardinal = 0;

  {: **************************************** TmyGUID *************************************** :}

  {: ---------------------------------------- default --------------------------------------- :}

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: String): TmyGUID;
  begin
    if (aGuid <> '') then
      begin
        Result := TmyGUID.CreateEmpty;
        Result.FromString(aGuid)
      end
    else
      begin
        Result := TmyGUID.CreateNew;
      end;
  end;

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: TmyGUID): TmyGUID;
  begin
    Result := aGuid;
  end;

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: PmyGUID): TmyGUID;
  begin
    Result := aGuid^;
  end;

  //: 2023-10-30
  class function TmyGUID.CreateEmpty: TmyGUID;
  begin
    Result.TS1 := 0;
    Result.TS2 := 0;
    Result.C := 0;
  end;

  //: 2023-10-30
  class function TmyGUID.CreateNew: TmyGUID;
  begin
    customTS2 := GetTickCount;
    Result.TS1 := customTS1;
    Result.TS2 := customTS2;
    Result.C := customC;
    if (customC = MaxCardinal) then
      customC := 0
    else
      Inc(customC);
  end;

  //: 2023-10-30
  class function TmyGUID.StringIsValidGuid(const aGuid: String): Boolean;
  var
    I: Integer;
    C: Char;
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    if (Length(aGuid) = 27) then
      begin
        Result := True;
        for I := 1 to Length(aGuid) do
          begin
            C := aGuid[I];
            case I of
              1:
                if C <> '#then
                  begin
                    Result := False;
                    Break;
                  end;
              10, 19:
                if C <> '-then
                  begin
                    Result := False;
                    Break;
                  end;
            else
              if not CharInSet(C, ['0'..'9', 'A'..'F']) then
                begin
                  Result := False;
                  Break;
                end;
            end;
          end;
      end
    else
      Result := False;
  end;

  //: 2023-10-30
  class operator TmyGUID.Equal(const Left, Right: TmyGUID): Boolean;
  begin
    Result := ((Left.TS1 = Right.TS1) and (Left.TS2 = Right.TS2) and (Left.C = Right.C));
  end;

  //: 2023-10-30
  class operator TmyGUID.NotEqual(const Left, Right: TmyGUID): Boolean;
  begin
    Result := ((Left.TS1 <> Right.TS1) or (Left.TS2 <> Right.TS2) or (Left.C <> Right.C));
  end;

  //: 2023-10-30
  function TmyGuid.GetHashCode: Integer;
  begin
    Result := 17;
    Result := Result * 397 + Integer(C);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS1, sizeOf(Cardinal), 5);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS2, sizeOf(Cardinal), 7);
  end;

  //: 2023-10-30
  function TmyGUID.IsEmpty: Boolean;
  begin
    Result := ((TS1 = 0) and (Ts2 = 0) and (C = 0));
  end;

  function TmyGUID.ToString: String;
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    Result := '#' + TS1.ToHexString + '-' + TS2.ToHexString + '-' + C.ToHexString;
  end;

  //: 2023-10-30
  procedure TmyGUID.DoEmpty;
  begin
    TS1 := 0;
    TS2 := 0;
    C := 0;
  end;

  //: 2023-10-30
  procedure TmyGUID.DoNew;
  var
    lGuid: TmyGUID;
  begin
    lGuid := CreateNew;
    TS1 := lGuid.TS1;
    TS2 := lGuid.TS2;
    C := lGuid.C;
  end;

  //: 2023-10-30
  procedure TmyGUID.FromString(const aGuid: String);
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    if (StringIsValidGuid(aGuid)) then
      begin
        TS1 := StrToInt('$' + Copy(aGuid, 2, 8));
        TS2 := StrToInt('$' + Copy(aGuid, 11, 8));
        C := StrToInt('$' + Copy(aGuid, 20, 8));
      end
    else
      begin
        TS1 := 0;
        Ts2 := 0;
        C := 0;
      end;
  end;

  //: 2023-10-30
  procedure TmyGUID.ReadFromStream(const aStream: TMemoryStream);
  begin
    aStream.ReadData(C);
    aStream.ReadData(TS1);
    aStream.ReadData(Ts2);
  end;

  //: 2023-10-30
  procedure TmyGUID.WriteToStream(const aStream: TMemoryStream);
  begin
    aStream.WriteData(C);
    aStream.WriteData(TS1);
    aStream.WriteData(Ts2);
  end;

initialization

  //: 2023-10-30
  customTS1 := GetTickCount;
  customTS2 := GetTickCount;
  customC := 0;

end.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von paule32.jk
paule32.jk

Registriert seit: 24. Sep 2022
Ort: Planet Erde
218 Beiträge
 
Delphi 11 Alexandria
 
#33

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 14:09
Vielen Dank für Deinen Code.
Ich würde da noch eine Copyright oder PD Notiz machen ...

Nur mal so als Idee:

vielleicht könntest Du ja den Code auch dafür verwenden, wenn Du mit RPC Gedanken spielst ?
weil, für MIDL und Co. ja viele solcher GUID's verwendet werden.

vielleicht könntest Du ja noch statt einen MemoryStream, ein FileStream einbauen, damit man dann ein Template für die MIDL RPC Dingends hat.

vielleicht könntest Du dann ja auch noch TRY EXCEPT Blöcke einbauen, die dann Fehler abfangen, wenn zum Beispiel Daten geschrieben werden sollen, auf denen man dann keinen Zugriff hat ...

nur mal so gedacht...
Frag doch einfach
Alles was nicht programmiert werden kann, wird gelötet
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.468 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#34

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 16:08
Das braucht natürlich einiges an Speicherplatz. Ich habe mich jetzt für GetTickCount entschieden, das die Systemlaufzeit als Cardinalwert zurück liefert.
Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...
Thomas Mueller
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.014 Beiträge
 
Delphi 12 Athens
 
#35

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 16:12
Auch die Auflösung von GetTickCount ist eher überschaubar. Eventuell wäre TTimeStamp eine Alternative.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Michael II
Online

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
730 Beiträge
 
Delphi 11 Alexandria
 
#36

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 16:17
Die erzeugten Werte sollten GLOBAL (GUID) möglichst kollisionsfrei sein. CreateGUID(NewGUID); guid := GUIDToString(NewGUID); schneidet wohl in den meisten Anwendungsfällen besser ab als eine "Lösung" via TDateTime oder GetTickCount. Ich nenne mal deinen Vorschlag LUID (L für lokal) und den üblichen 128 Bit Wert GUID.

TDateTime. TDateTime ist ein double. 8 Byte. Wenn du deine Funktion zwischen Jahr 1 und Jahr 9999 anbieten willst, dann speicherst du für Zeitspempel1 9999*365.25*24*60*60*1000 voneinander verschiedene Werte ab, dazu benötigst du eigentlich nur 48.5 Bits (und nicht 64). Da dein zweiter Zeitstempel z2 zeitlich nach dem ersten liegt, ist der Informationsgehalt von z2 noch tiefer. Nehmen wir mal an, z2 liege maximal 100 Jahre nach z1; dann sind das weitere 41.5 Bit Infos. Zusammen mit deinem 2 Byte Zähler, speicherst du 92 Bit Infos in deinen 144Bits, verschwendest also 52 Bits.

Eine GUID, wie du sie dir einfach via Delphi unter Windows abholen kannst nutzt global (über alle Geräte) 128 Bits.

LUID ist also 128-92=36 Bit schwächer; erzeugt 2^36 Mal weniger Werte als GUID.

Das wirkt sich natürlich sehr schlecht auf die Kollisionswahrscheinlichkeit aus.
Wie viele LUIDs kannst du ausgeben, bis die Wahrscheinlichkeit mindestens einer Kollision auf >50% steigt?
Wären deine LUIDs gleichverteilt (wäre optimal; sie sind es nicht, da du zum Beispiel im Jahr 2023 kein Zeitstempel1 2045 ausgegeben wird), dann wären es k=1/2+sqrt(1/4+2*N*ln(2))*, wobei N=2^92 die Anzahl möglicher LUIDs. Für GUIDs gilt N=2^128.

92 Bit-Werte kollidieren gemäss * bezogen auf den Fall "mind. 1 Kollision" 2^18 mal schneller als die 128 Bit GUIDs. Effektiv tun es deine LUIDs noch viel rascher, weil deine LUIDs "aufsteigend" und damit weniger "zufällig/gleichverteilt" als die GUIDs ausgegeben werden.

Rollo63 hat Infos zum Thema Kollisionen verlinkt. Es gibt dort ein Beispiel, in welchem die Ausgabe von 1 Milliarde GUIDs/sec erst nach rund 86 Jahren mit p=0.5 zu mindestens einer Kollision führt. Selbst bei optimalen 92 Bit Werten dauerte es bei gleicher Ausgabegeschwindigkeit (1 Mio 92 Bit Werte/Millisekunde(!)) nur ungefähr 3 Stunden bis es in 50% aller Fälle zu mindestens einer Kollision kommt.

Der GetTickCount Vorschlag schneidet auch nicht gut ab; da verwendest du insgesamt 4+4+4 Bytes=96 Bits.(Nebenbei: Es gibt auch GetTickCount64). GetTickCount/64 hat laut microsoft immer noch eine Auflösung von nur 10 bis 16ms (wirkt sich negativ auf die Kollisionswahrscheinlichkeit p=1-N^k/((N-k)!*N^k) aus). Bei 16ms Auflösung verlierst du zum Beispiel 2*4=8 Bits an Infos, hast also noch 88 Bytes Informationsgehalt.

Sinspin erwähnte hochauflösende Timer. Diese hätten immerhin eine bessere Auflösung als TDateTime, gettickcount, gettickcount64.

Die GUID, welche du in Delphi via CreateGUID(NewGUID); abrufen kannst sind wohl in den meisten Anwendungsfällen genügend kollisionsfrei.

Wenn du kollisionsfreie IDs benötigst, dann musst du Eigenschaften der Geräte nutzen, welche jedes Gerät eindeutig identifizieren oder aber du verwendest wie weiter oben erwähnt wurde eine zentrale Vergabestelle (da würde dann auch ein einfacher Zähler genügen).
Michael Gasser

Geändert von Michael II (31. Okt 2023 um 07:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von paule32.jk
paule32.jk

Registriert seit: 24. Sep 2022
Ort: Planet Erde
218 Beiträge
 
Delphi 11 Alexandria
 
#37

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 19:45
ist schon interessant der Link zu Microsoft.
Allerdings weiß ich gerade nicht, wie die Testdaten zustande gekommen sind - habe das nur so flüchtig überflogen.
Aber die Tabelle mit "1 Woche Messunsicherheit von 6,08 Sekunden" ist schon nah am Limit.
Ich nehme mal an, das die modernen Computer mittels NTP Server angepasst werden, sofern Internet verfügbar ist.
Geht wohl nicht tiefer auf Comsumer PC...
Frag doch einfach
Alles was nicht programmiert werden kann, wird gelötet
  Mit Zitat antworten Zitat
skybibo

Registriert seit: 23. Jun 2008
Ort: NRW
22 Beiträge
 
Delphi 12 Athens
 
#38

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 30. Okt 2023, 19:57
Zitat:
Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.

Ich verwende daher seit Jahren GetTickCount64. Wenn dann der Zähler in ca. 585 Millionen Jahren wieder auf 0 geht interessiert mich nicht.
Bernd
  Mit Zitat antworten Zitat
Benutzerbild von Sinspin
Sinspin

Registriert seit: 15. Sep 2008
Ort: Dubai
618 Beiträge
 
Delphi 10.3 Rio
 
#39

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 31. Okt 2023, 07:35
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.
Da gab es einige die mit Win95 Recorde aufgestellt haben. Inclusive mir.
Mein Rechner lief 24/7 unter Vollast. Erst für SETI@Home dann für Rosetta@Home. Ich brauchte im Winter jedenfalls keine Heizung.
Wenn ich mich recht erinnere wurde Windows anfangs instabil wenn man über 49 Tage kam. Das hat sich irgendwann geändert.
Nur das Problem dass die Netzwerkkarte nach einigen GB nicht mehr wollte, das blieb über ein paar Windows Versionen hinweg ein Problem. Spätestens dann war es Zeit den Rechner mal neu zu starten.
Stefan
Nur die Besten sterben jung
A constant is a constant until it change.
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.468 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#40

AW: TGUID - einzigartige ID auf andere Computer Systeme ?

  Alt 31. Okt 2023, 08:43
Zitat:
Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.

Ich verwende daher seit Jahren GetTickCount64. Wenn dann der Zähler in ca. 585 Millionen Jahren wieder auf 0 geht interessiert mich nicht.
Wie einen die Erinnerung doch täuschen kann. Ich hatte kurz überlegt, es nachzurechnen, war aber dann zu faul. Zu meiner Entlastung: Es ist so ca. 25 Jahre her, dass ich mich mit dem Problem auseinandersetzen musste. Eines der Programme, die bei diesem Überlauf abstürzten, war meines (allerdings wurde das nur intern verwendet). Damals ging es um Windows NT4 und das lief über Monate stabil (Win95/98/ME brauchte ich zum Glück nie benutzen). GetTickCount64 gab es damals noch nicht, soweit ich mich errinnere. Ich meine, ich hätte damals dann "einfach" den Überlauf im Code berücksichtigt.

/AlterMannGebrabbelEnde
Thomas Mueller
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 7   « Erste     234 56     Letzte »    


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:49 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz