Universally Unique Identifiers (UUIDs), also known as GUIDs (Globally Unique Identifiers) in Windows development, are 128-bit values that provide unique identification across distributed systems. In Delphi programming, GUIDs are essential for COM interfaces, database primary keys, distributed applications, and ensuring uniqueness without centralized coordination. Whether you're developing desktop applications with VCL/FMX or server applications, understanding UUID generation is crucial.
This comprehensive guide explores multiple approaches to generate UUIDs in Delphi applications, covering both native RTL functions and Windows API calls. We'll examine implementation strategies for different Delphi versions, from classic Delphi 7 to the latest RAD Studio releases, as well as cross-platform considerations for FireMonkey applications. The techniques presented here also apply to Free Pascal and Lazarus development.
The simplest and most common way to generate a UUID in Delphi is using the built-in CreateGUID function from the System.SysUtils unit. This method works across all Delphi versions and platforms.
program GenerateUUID;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
MyGUID: TGUID;
GUIDString: string;
begin
try
// Generate a new GUID
if CreateGUID(MyGUID) = S_OK then
begin
// Convert GUID to string representation
GUIDString := GUIDToString(MyGUID);
WriteLn('Generated UUID: ', GUIDString);
// Output example: Generated UUID: {8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75}
// Alternative: Get string without braces
GUIDString := MyGUID.ToString;
WriteLn('Without braces: ', GUIDString);
// Output example: Without braces: 8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75
end
else
WriteLn('Failed to create GUID');
ReadLn;
except
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.
CreateGUID generates a Version 4 (random) UUID using the operating system's cryptographically secure random number generator. On Windows, it calls CoCreateGuid internally, while on other platforms it uses appropriate system functions. The function returns S_OK (0) on success. The TGUID record type represents the GUID structure, and GUIDToString converts it to the standard string format with braces.
For Windows-specific applications or when you need more control, you can directly call the Windows API CoCreateGuid function. This approach requires the Winapi.ActiveX unit.
program WindowsAPIGUID;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
Winapi.Windows,
Winapi.ActiveX;
function GenerateWindowsGUID: string;
var
NewGUID: TGUID;
hr: HResult;
begin
// Initialize COM (required for CoCreateGuid)
CoInitialize(nil);
try
// Call Windows API directly
hr := CoCreateGuid(NewGUID);
if Succeeded(hr) then
begin
// Convert to string format
Result := GUIDToString(NewGUID);
end
else
begin
raise Exception.CreateFmt('CoCreateGuid failed with error: %d', [hr]);
end;
finally
// Cleanup COM
CoUninitialize;
end;
end;
begin
try
WriteLn('Windows API GUID: ', GenerateWindowsGUID);
// Generate multiple GUIDs
WriteLn('Generating 5 GUIDs:');
for var i := 1 to 5 do
WriteLn(Format(' GUID %d: %s', [i, GenerateWindowsGUID]));
ReadLn;
except
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.
This method directly interfaces with Windows COM subsystem to generate GUIDs. CoCreateGuid is the underlying Windows API that CreateGUID calls on Windows platforms. While this approach requires COM initialization, it provides direct access to Windows GUID generation and can be useful when working with COM interfaces or when you need to ensure you're using the Windows-specific implementation.
Delphi allows flexible formatting of GUIDs to meet various requirements, such as removing braces, using different separators, or creating custom representations for specific systems.
program FormattedGUIDs;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TGUIDHelper = record helper for TGUID
function ToCompactString: string;
function ToUppercaseString: string;
function ToRegistryFormat: string;
function ToURNFormat: string;
end;
function TGUIDHelper.ToCompactString: string;
begin
// Remove all formatting (32 hex digits)
Result := Format('%.8x%.4x%.4x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x',
[D1, D2, D3, D4[0], D4[1], D4[2], D4[3], D4[4], D4[5], D4[6], D4[7]]);
end;
function TGUIDHelper.ToUppercaseString: string;
begin
Result := UpperCase(ToString);
end;
function TGUIDHelper.ToRegistryFormat: string;
begin
// Registry format uses braces
Result := GUIDToString(Self);
end;
function TGUIDHelper.ToURNFormat: string;
begin
// URN format: urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Result := 'urn:uuid:' + ToString;
end;
var
MyGUID: TGUID;
begin
CreateGUID(MyGUID);
WriteLn('Standard format: ', MyGUID.ToString);
WriteLn('With braces: ', GUIDToString(MyGUID));
WriteLn('Compact (no dashes):', MyGUID.ToCompactString);
WriteLn('Uppercase: ', MyGUID.ToUppercaseString);
WriteLn('Registry format: ', MyGUID.ToRegistryFormat);
WriteLn('URN format: ', MyGUID.ToURNFormat);
// Custom formatting with specific separators
WriteLn('Custom format: ',
Format('%.8x_%.4x_%.4x_%.2x%.2x_%.2x%.2x%.2x%.2x%.2x%.2x',
[MyGUID.D1, MyGUID.D2, MyGUID.D3, MyGUID.D4[0], MyGUID.D4[1],
MyGUID.D4[2], MyGUID.D4[3], MyGUID.D4[4], MyGUID.D4[5],
MyGUID.D4[6], MyGUID.D4[7]]));
ReadLn;
end.
This example demonstrates various GUID formatting options using a record helper. The TGUID record contains fields D1 (longword), D2 and D3 (word), and D4 (array of 8 bytes) that represent the GUID structure. You can access these fields directly for custom formatting. The compact format is useful for URLs or when storage space is limited, while the URN format is used in various Internet standards.
While random GUIDs are suitable for most cases, sometimes you need deterministic UUIDs that can be regenerated from specific inputs. This implementation creates Version 5 UUIDs using SHA-1 hashing.
program DeterministicGUID;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Hash;
type
// Standard namespace GUIDs from RFC 4122
TNamespaceGUID = record
const DNS: TGUID = '{6ba7b810-9dad-11d1-80b4-00c04fd430c8}';
const URL: TGUID = '{6ba7b811-9dad-11d1-80b4-00c04fd430c8}';
const OID: TGUID = '{6ba7b812-9dad-11d1-80b4-00c04fd430c8}';
const X500: TGUID = '{6ba7b814-9dad-11d1-80b4-00c04fd430c8}';
end;
function CreateNameBasedGUID(const NamespaceGUID: TGUID; const Name: string): TGUID;
var
Hash: THashSHA1;
HashBytes: TBytes;
NamespaceBytes: TBytes;
NameBytes: TBytes;
CombinedBytes: TBytes;
i: Integer;
begin
// Convert namespace GUID to bytes
SetLength(NamespaceBytes, 16);
Move(NamespaceGUID.D1, NamespaceBytes[0], 4);
Move(NamespaceGUID.D2, NamespaceBytes[4], 2);
Move(NamespaceGUID.D3, NamespaceBytes[6], 2);
Move(NamespaceGUID.D4[0], NamespaceBytes[8], 8);
// Swap byte order for network byte order (big-endian)
// D1 is 4 bytes
for i := 0 to 1 do
begin
var temp := NamespaceBytes[i];
NamespaceBytes[i] := NamespaceBytes[3-i];
NamespaceBytes[3-i] := temp;
end;
// D2 is 2 bytes
var temp := NamespaceBytes[4];
NamespaceBytes[4] := NamespaceBytes[5];
NamespaceBytes[5] := temp;
// D3 is 2 bytes
temp := NamespaceBytes[6];
NamespaceBytes[6] := NamespaceBytes[7];
NamespaceBytes[7] := temp;
// Convert name to UTF-8 bytes
NameBytes := TEncoding.UTF8.GetBytes(Name);
// Combine namespace and name
SetLength(CombinedBytes, Length(NamespaceBytes) + Length(NameBytes));
Move(NamespaceBytes[0], CombinedBytes[0], Length(NamespaceBytes));
Move(NameBytes[0], CombinedBytes[Length(NamespaceBytes)], Length(NameBytes));
// Calculate SHA-1 hash
Hash := THashSHA1.Create;
Hash.Update(CombinedBytes);
HashBytes := Hash.HashAsBytes;
// Copy first 16 bytes to GUID
Move(HashBytes[0], Result.D1, 4);
Move(HashBytes[4], Result.D2, 2);
Move(HashBytes[6], Result.D3, 2);
Move(HashBytes[8], Result.D4[0], 8);
// Set version (5) and variant bits
Result.D3 := (Result.D3 and $0FFF) or $5000; // Version 5
Result.D4[0] := (Result.D4[0] and $3F) or $80; // Variant 10
end;
begin
try
var TestName := 'example.com/user/12345';
// Generate deterministic GUIDs
var GUID1 := CreateNameBasedGUID(TNamespaceGUID.URL, TestName);
WriteLn('URL-based GUID for "', TestName, '":');
WriteLn(' ', GUIDToString(GUID1));
// Same input produces same output
var GUID2 := CreateNameBasedGUID(TNamespaceGUID.URL, TestName);
WriteLn(' Same input: ', GUIDToString(GUID2));
WriteLn(' Equal: ', GUIDToString(GUID1) = GUIDToString(GUID2));
WriteLn;
// Different namespaces produce different GUIDs
var GUID3 := CreateNameBasedGUID(TNamespaceGUID.DNS, 'example.com');
WriteLn('DNS-based GUID for "example.com":');
WriteLn(' ', GUIDToString(GUID3));
ReadLn;
except
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.
This implementation creates RFC 4122 Version 5 UUIDs using SHA-1 hashing. The same namespace and name combination always produces the same UUID, making it ideal for distributed systems where different nodes need to generate identical identifiers for the same resource. The namespace provides context (DNS, URL, etc.) while the name is the specific identifier. Note that byte order conversion is necessary because the RFC specifies network byte order.
For applications that frequently use UUIDs, it's beneficial to create a utility unit that centralizes UUID generation logic. Here's a comprehensive utility unit for Delphi applications:
unit UUIDUtils;
interface
uses
System.SysUtils, System.Hash;
type
/// <summary>
/// Utility class for UUID/GUID generation and manipulation
/// </summary>
TUUIDGenerator = class
public
type
TUUIDVersion = (uvRandom, uvTimeBased, uvNameBased);
class var
// Standard namespaces from RFC 4122
NamespaceDNS: TGUID;
NamespaceURL: TGUID;
NamespaceOID: TGUID;
NamespaceX500: TGUID;
private
class constructor Create;
class function SwapEndian(const AGUID: TGUID): TGUID;
public
/// <summary>Generate a random UUID (Version 4)</summary>
class function NewGUID: TGUID;
/// <summary>Generate a sequential UUID for database optimization</summary>
class function NewSequentialGUID: TGUID;
/// <summary>Generate a name-based UUID (Version 5)</summary>
class function NewNameBasedGUID(const NamespaceGUID: TGUID;
const Name: string): TGUID;
/// <summary>Generate URL-based deterministic UUID</summary>
class function NewURLBasedGUID(const URL: string): TGUID;
/// <summary>Generate DNS-based deterministic UUID</summary>
class function NewDNSBasedGUID(const DNS: string): TGUID;
/// <summary>Parse string to GUID with validation</summary>
class function TryParseGUID(const S: string; out GUID: TGUID): Boolean;
/// <summary>Check if GUID is empty/nil</summary>
class function IsEmptyGUID(const GUID: TGUID): Boolean;
/// <summary>Get GUID without braces or hyphens</summary>
class function GetCompactGUID(const GUID: TGUID): string;
end;
implementation
uses
System.DateUtils, Winapi.Windows;
{ TUUIDGenerator }
class constructor TUUIDGenerator.Create;
begin
// Initialize standard namespaces
NamespaceDNS := StringToGUID('{6ba7b810-9dad-11d1-80b4-00c04fd430c8}');
NamespaceURL := StringToGUID('{6ba7b811-9dad-11d1-80b4-00c04fd430c8}');
NamespaceOID := StringToGUID('{6ba7b812-9dad-11d1-80b4-00c04fd430c8}');
NamespaceX500 := StringToGUID('{6ba7b814-9dad-11d1-80b4-00c04fd430c8}');
end;
class function TUUIDGenerator.NewGUID: TGUID;
begin
if CreateGUID(Result) <> S_OK then
raise Exception.Create('Failed to create GUID');
end;
class function TUUIDGenerator.NewSequentialGUID: TGUID;
var
Timestamp: Int64;
Counter: Word;
begin
// Generate base GUID
Result := NewGUID;
// Get current timestamp
Timestamp := DateTimeToUnix(Now, False) * 10000000;
// Embed timestamp in first 6 bytes for sequential ordering
Result.D1 := LongWord(Timestamp shr 16);
Result.D2 := Word(Timestamp);
// Keep version 4 and variant bits
Result.D3 := (Result.D3 and $0FFF) or $4000;
Result.D4[0] := (Result.D4[0] and $3F) or $80;
end;
class function TUUIDGenerator.SwapEndian(const AGUID: TGUID): TGUID;
begin
Result := AGUID;
// Swap D1 (4 bytes)
Result.D1 := ((AGUID.D1 and $000000FF) shl 24) or
((AGUID.D1 and $0000FF00) shl 8) or
((AGUID.D1 and $00FF0000) shr 8) or
((AGUID.D1 and $FF000000) shr 24);
// Swap D2 (2 bytes)
Result.D2 := ((AGUID.D2 and $00FF) shl 8) or
((AGUID.D2 and $FF00) shr 8);
// Swap D3 (2 bytes)
Result.D3 := ((AGUID.D3 and $00FF) shl 8) or
((AGUID.D3 and $FF00) shr 8);
end;
class function TUUIDGenerator.NewNameBasedGUID(const NamespaceGUID: TGUID;
const Name: string): TGUID;
var
Hash: THashSHA1;
HashBytes: TBytes;
NamespaceBytes: TBytes;
SwappedGUID: TGUID;
begin
// Convert to network byte order
SwappedGUID := SwapEndian(NamespaceGUID);
// Prepare data for hashing
SetLength(NamespaceBytes, 16);
Move(SwappedGUID, NamespaceBytes[0], 16);
// Calculate hash
Hash := THashSHA1.Create;
Hash.Update(NamespaceBytes);
Hash.Update(TEncoding.UTF8.GetBytes(Name));
HashBytes := Hash.HashAsBytes;
// Create GUID from hash
Move(HashBytes[0], Result, 16);
// Convert back from network byte order
Result := SwapEndian(Result);
// Set version 5 and variant
Result.D3 := (Result.D3 and $0FFF) or $5000;
Result.D4[0] := (Result.D4[0] and $3F) or $80;
end;
class function TUUIDGenerator.NewURLBasedGUID(const URL: string): TGUID;
begin
Result := NewNameBasedGUID(NamespaceURL, URL);
end;
class function TUUIDGenerator.NewDNSBasedGUID(const DNS: string): TGUID;
begin
Result := NewNameBasedGUID(NamespaceDNS, DNS);
end;
class function TUUIDGenerator.TryParseGUID(const S: string;
out GUID: TGUID): Boolean;
begin
try
GUID := StringToGUID(S);
Result := True;
except
Result := False;
end;
end;
class function TUUIDGenerator.IsEmptyGUID(const GUID: TGUID): Boolean;
const
EmptyGUID: TGUID = '{00000000-0000-0000-0000-000000000000}';
begin
Result := CompareMem(@GUID, @EmptyGUID, SizeOf(TGUID));
end;
class function TUUIDGenerator.GetCompactGUID(const GUID: TGUID): string;
begin
Result := Format('%.8x%.4x%.4x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x',
[GUID.D1, GUID.D2, GUID.D3, GUID.D4[0], GUID.D4[1], GUID.D4[2],
GUID.D4[3], GUID.D4[4], GUID.D4[5], GUID.D4[6], GUID.D4[7]]);
end;
end.
This utility unit provides a comprehensive set of UUID generation methods encapsulated in a class with class methods. It includes random UUID generation, sequential UUIDs for database optimization, and deterministic name-based UUIDs following RFC 4122. The unit handles endianness conversion for proper Version 5 UUID generation and provides helper methods for parsing and formatting. You can easily extend this unit with additional functionality like Version 1 (time-based) or Version 3 (MD5-based) UUID generation.
When working with GUIDs from external sources or user input, proper validation is crucial. Here's how to parse and validate GUIDs in Delphi applications:
program ValidateGUIDs;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.RegularExpressions;
type
TGUIDValidator = class
private
const
// RFC 4122 compliant GUID pattern
GUIDPattern = '^[{(]?[0-9A-Fa-f]{8}[-]?([0-9A-Fa-f]{4}[-]?){3}[0-9A-Fa-f]{12}[)}]?$';
public
class function IsValidGUID(const Value: string): Boolean;
class function TryParseGUID(const Value: string; out GUID: TGUID): Boolean;
class function NormalizeGUID(const Value: string): string;
class function ExtractGUIDFromText(const Text: string): TArray<string>;
end;
class function TGUIDValidator.IsValidGUID(const Value: string): Boolean;
var
RegEx: TRegEx;
begin
RegEx := TRegEx.Create(GUIDPattern);
Result := RegEx.IsMatch(Value);
end;
class function TGUIDValidator.TryParseGUID(const Value: string;
out GUID: TGUID): Boolean;
var
NormalizedValue: string;
begin
Result := False;
// First check with regex
if not IsValidGUID(Value) then
Exit;
try
// Normalize the GUID string
NormalizedValue := NormalizeGUID(Value);
// Try to convert
GUID := StringToGUID(NormalizedValue);
Result := True;
except
// Invalid format
Result := False;
end;
end;
class function TGUIDValidator.NormalizeGUID(const Value: string): string;
var
CleanValue: string;
begin
// Remove all non-hex characters
CleanValue := TRegEx.Replace(Value, '[^0-9A-Fa-f]', '');
// Check if we have exactly 32 hex digits
if Length(CleanValue) <> 32 then
raise Exception.Create('Invalid GUID length');
// Format as standard GUID
Result := Format('{%s-%s-%s-%s-%s}',
[Copy(CleanValue, 1, 8),
Copy(CleanValue, 9, 4),
Copy(CleanValue, 13, 4),
Copy(CleanValue, 17, 4),
Copy(CleanValue, 21, 12)]);
end;
class function TGUIDValidator.ExtractGUIDFromText(const Text: string): TArray<string>;
var
RegEx: TRegEx;
Matches: TMatchCollection;
Match: TMatch;
i: Integer;
begin
RegEx := TRegEx.Create(GUIDPattern);
Matches := RegEx.Matches(Text);
SetLength(Result, Matches.Count);
for i := 0 to Matches.Count - 1 do
Result[i] := Matches[i].Value;
end;
// Test the validator
var
TestStrings: array[0..5] of string = (
'{8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75}', // Valid with braces
'8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75', // Valid without braces
'8C2D56F08A1E4B6CA8D2AF3A99B11F75', // Valid without any formatting
'(8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75)', // Valid with parentheses
'not-a-guid', // Invalid
'8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F7' // Invalid (too short)
);
TestGUID: TGUID;
TestString: string;
begin
try
WriteLn('GUID Validation Tests:');
WriteLn('='*50);
for TestString in TestStrings do
begin
Write(Format('%-40s: ', [TestString]));
if TGUIDValidator.TryParseGUID(TestString, TestGUID) then
WriteLn('Valid - Parsed as ', GUIDToString(TestGUID))
else
WriteLn('Invalid');
end;
WriteLn;
WriteLn('Extracting GUIDs from text:');
WriteLn('='*50);
var SampleText := 'The user ID is {8C2D56F0-8A1E-4B6C-A8D2-AF3A99B11F75} ' +
'and the session ID is 123e4567-e89b-12d3-a456-426614174000.';
var ExtractedGUIDs := TGUIDValidator.ExtractGUIDFromText(SampleText);
WriteLn('Text: ', SampleText);
WriteLn('Found GUIDs:');
for TestString in ExtractedGUIDs do
WriteLn(' - ', TestString);
ReadLn;
except
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.
This validation example demonstrates comprehensive GUID validation using regular expressions. The TGUIDValidator class can validate GUIDs in various formats (with/without braces, hyphens, or parentheses), normalize them to a standard format, and extract GUIDs from larger text blocks. The regex pattern matches all common GUID representations while the normalization function ensures consistent formatting. This is particularly useful when processing user input or data from external systems.
When generating GUIDs at scale in Delphi applications, performance becomes critical. Here's how to optimize GUID generation and measure performance:
program GUIDPerformance;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.Diagnostics, System.Classes,
System.Generics.Collections, System.Threading;
type
TGUIDCache = class
private
FCache: TThreadList<TGUID>;
FCacheSize: Integer;
FRefillThreshold: Integer;
procedure RefillCache;
public
constructor Create(ACacheSize: Integer = 1000);
destructor Destroy; override;
function GetGUID: TGUID;
property CacheSize: Integer read FCacheSize;
end;
constructor TGUIDCache.Create(ACacheSize: Integer);
begin
inherited Create;
FCacheSize := ACacheSize;
FRefillThreshold := ACacheSize div 4;
FCache := TThreadList<TGUID>.Create;
RefillCache;
end;
destructor TGUIDCache.Destroy;
begin
FCache.Free;
inherited;
end;
procedure TGUIDCache.RefillCache;
var
List: TList<TGUID>;
i: Integer;
NewGUID: TGUID;
begin
List := FCache.LockList;
try
// Fill cache to capacity
while List.Count < FCacheSize do
begin
CreateGUID(NewGUID);
List.Add(NewGUID);
end;
finally
FCache.UnlockList;
end;
end;
function TGUIDCache.GetGUID: TGUID;
var
List: TList<TGUID>;
begin
List := FCache.LockList;
try
if List.Count = 0 then
RefillCache;
Result := List.Last;
List.Delete(List.Count - 1);
// Refill cache asynchronously if below threshold
if List.Count < FRefillThreshold then
begin
TTask.Run(procedure
begin
RefillCache;
end);
end;
finally
FCache.UnlockList;
end;
end;
// Benchmark different approaches
procedure BenchmarkGUIDGeneration(Count: Integer);
var
Stopwatch: TStopwatch;
GUIDs: TArray<TGUID>;
i: Integer;
Cache: TGUIDCache;
procedure BenchmarkStandard;
begin
Stopwatch := TStopwatch.StartNew;
SetLength(GUIDs, Count);
for i := 0 to Count - 1 do
CreateGUID(GUIDs[i]);
Stopwatch.Stop;
WriteLn(Format('Standard CreateGUID: %d ms for %d GUIDs (%.2f GUIDs/ms)',
[Stopwatch.ElapsedMilliseconds, Count,
Count / Max(1, Stopwatch.ElapsedMilliseconds)]));
end;
procedure BenchmarkCached;
begin
Cache := TGUIDCache.Create(1000);
try
Stopwatch := TStopwatch.StartNew;
SetLength(GUIDs, Count);
for i := 0 to Count - 1 do
GUIDs[i] := Cache.GetGUID;
Stopwatch.Stop;
WriteLn(Format('Cached generation: %d ms for %d GUIDs (%.2f GUIDs/ms)',
[Stopwatch.ElapsedMilliseconds, Count,
Count / Max(1, Stopwatch.ElapsedMilliseconds)]));
finally
Cache.Free;
end;
end;
procedure BenchmarkParallel;
begin
Stopwatch := TStopwatch.StartNew;
SetLength(GUIDs, Count);
TParallel.For(0, Count - 1,
procedure(Index: Integer)
begin
CreateGUID(GUIDs[Index]);
end);
Stopwatch.Stop;
WriteLn(Format('Parallel generation: %d ms for %d GUIDs (%.2f GUIDs/ms)',
[Stopwatch.ElapsedMilliseconds, Count,
Count / Max(1, Stopwatch.ElapsedMilliseconds)]));
end;
begin
WriteLn(Format('Benchmarking generation of %d GUIDs...', [Count]));
WriteLn('='*60);
BenchmarkStandard;
BenchmarkCached;
BenchmarkParallel;
WriteLn;
WriteLn('Memory usage:');
WriteLn(Format(' Single GUID: %d bytes', [SizeOf(TGUID)]));
WriteLn(Format(' %d GUIDs: %.2f MB', [Count, (Count * SizeOf(TGUID)) / (1024 * 1024)]));
end;
begin
try
// Test with different sizes
BenchmarkGUIDGeneration(10000);
WriteLn;
BenchmarkGUIDGeneration(100000);
WriteLn;
BenchmarkGUIDGeneration(1000000);
ReadLn;
except
on E: Exception do
WriteLn('Error: ', E.Message);
end;
end.
This performance optimization example demonstrates three approaches to high-volume GUID generation: standard sequential generation, cached generation with background refilling, and parallel generation using TParallel. The cached approach pre-generates GUIDs and refills the cache asynchronously, reducing latency for applications that need GUIDs on-demand. Parallel generation leverages multiple CPU cores for bulk operations. The benchmarks help identify the most suitable approach for your specific use case. Note that CreateGUID is thread-safe, making parallel generation safe without additional synchronization.
When implementing UUID generation in Delphi applications, choose the appropriate method based on your requirements. For general-purpose unique identifiers, CreateGUID provides a simple, cross-platform solution. For Windows-specific applications requiring COM compatibility, direct API calls offer more control. Sequential GUIDs optimize database performance but sacrifice some randomness. Deterministic UUIDs enable distributed systems to generate consistent identifiers independently. Always validate external GUIDs and consider caching for high-performance scenarios.
Modern Delphi development benefits from the robust GUID support built into the RTL, with additional capabilities available through Windows APIs and custom implementations. Whether you're building desktop applications with VCL, cross-platform apps with FireMonkey, or server applications, the techniques presented in this guide provide a solid foundation for UUID implementation. Remember to consider thread safety, performance implications, and storage requirements when designing your UUID strategy. For database applications, evaluate whether sequential GUIDs provide meaningful performance benefits for your specific use case.
For quick UUID generation without writing code, you can use our online UUID generator tool, which provides instant UUID generation in various formats with a simple click.