12 숫자 고유 ID- 코드 안정성
-
22-08-2019 - |
문제
나는 하루 (24 시간) 동안 독특한 숫자를 원했습니다. 다음은 제가 생각해 낸 코드입니다. 나는 그 오류/가능한 위험에 대해 궁금해했다. '나는 믿습니다'이것은 하루에 12 자리 고유 번호를 보장합니다.
논리는 현재 날짜/시간 (hhmmssmmm)을 얻고 쿼리 성능 카운터 결과의 처음 4 바이트를 동의하는 것입니다.
__forceinline bool GetUniqueID(char caUID[MAX_STRING_LENGTH])
{
//Logic: Add HHMMSSmmm with mid 3 bytes of performance counter.
//Guarantees that in a single milli second band (0 to 999) the three bytes
//of performance counter would always be unique.
//1. Get system time, and use
bool bStatus = false;
try
{
SYSTEMTIME localtime;
GetLocalTime(&localtime);//Get local time, so that we may pull out HHMMSSmmm
LARGE_INTEGER li;
char cNT[MAX_STRING_LENGTH];//new time.
memset(cNT, '\0', sizeof(cNT));
try
{
//Try to get the performance counter,
//if one is provided by the OEM.
QueryPerformanceCounter(&li);//This function retrieves the current value of the
//high-resolution performance counter if one is provided by the OEM
//We use the first four bytes only of it.
sprintf(cNT, "%u", li.QuadPart);
}
catch(...)
{
//Not provided by OEM.
//Lets go with the GetTickCounts();
//ddHHMMSS + 4 bytes of dwTicks
sprintf(cNT,"%04d", GetTickCount());
}
//Get the first four bytes.
int iSkipTo = 0;//This is incase we'd decide to pull out next four bytes, rather than first four bytes.
int iGetChars = 4;//Number of chars to get.
char *pSub = (char*) malloc(iGetChars+1);//Clear memory
strncpy(pSub, cNT + iSkipTo, iGetChars);//Get string
pSub[iGetChars] = '\0'; //Mark end.
//Prepare unique id
sprintf(caUID, "%02d%02d%02d%3d%s",
localtime.wHour,
localtime.wMinute,
localtime.wSecond,
localtime.wMilliseconds,
pSub); //First four characters concat.
bStatus = true;
}
catch(...)
{
//Couldnt prepare. There was some problem.
bStatus = false;
}
return bStatus;
}
다음은 내가 얻는 출력입니다.
고유 : [125907 462224] 고유 : [125907 462225] 고유 : [125907 462226] 고유 : [125907 462227] 고유 : [125907 462228] 고유 : [125907 462230] 고유 : [125907 462221] 고유 : [125907 462221]. [125907 462233] 고유 : [125907 462234] 고유 : [125907 462235] 고유 : [125907 462237] 고유 : [125907 462238] 고유 : [125907 462239] 고유 : [125907 462240] 고유 : [125907 462240] 462243] 고유 : [125907 462244] 고유 : [125907 462245] 고유 : [125907 462246] 고유 : [125907 462247] 고유 : [125907 462248] 고유 : [125907 4622249] 독특한 : [125907 46251]에 의해 사용됩니다. 고유 : [125907 462253] 고유 : [125907 462254] 고유 : [125907 462255] 고유 : [125907 462256] 고유 : [125907 462257] 고유 : [125907 462258] Millisecond, 46 Unique : [125907 62261]. 622262] 고유 : [125907 622263] 고유 : [125907 622264] 고유 : [125907 622265] 고유 : [125907 622267] 고유 : [125907 622268] 고유 : [125907 622269] 독특한 : [125907 62270]에 의해. 고유 : [125907 622273] 고유 : [12 5907 622274] 고유 : [125907 622275] 고유 : [125907 622276] 고유 : [125907 622277] 고유 : [125907 622278] 고유 : [125907 622279] 고유 : [125907 622281] 고유 : [125907 622222281] ] 고유 : [125907 622284] 고유 : [125907 622285] 고유 : [125907 622286] 고유 : [125907 622288] 고유 : [125907 622289] 고유 : [125907 62290] 고유 : [125907 6629] 고유 : [125907 6222229]. : [125907 622293] 고유 : [125907 622295] 고유 : [125907 622296] 고유 : [125907 622297] 고유 : [125907 622298] 고유 : [125907 62299] 독특 : [125907 623 62300] 125907 622302] 고유 : [125907 622304] 고유 : [125907 622305] 고유 : [125907 622306] Millsecond 변경, 62 고유 : [125907 782308] 고유 : [125907 78231] 독특한 : [125907777 782311]. : [125907 782313] 고유 : [125907 782314] 고유 : [125907 782316] 고유 : [125907 782317] 고유 : [125907 782318] 고유 : [125907 782319] 고유 한 Millisecond, 125904949949] : [1259071402 498] 고유 : [1259071402499] 고유 : [1259071402500] 고유 : [1259071402502] 고유 : [1259071402503] 고유 : [1259071402504] 고유 : [1259071402505] 고유 : [125907071402507
이제 생성 된 ID를 목록에 보관하고 새 생성 ID를 목록의 기존 ID와 비교할 생각입니다. 그것이 이미 목록에 존재한다면, 나는 확실히 숫자를 건너 뛰고 다른 숫자를 생성 할 수 있지만, 확실히 분명히이 논리는 실패 할 것입니다.
귀하의 의견/제안/업데이트 등에 감사드립니다.
감사합니다 jt.
해결책
내 해결책은 시스템 시간을 얻고 그에 대한 카운터를 추가하는 것이 었습니다 (의사 코드).
static int counter = 0;
static Time lastTime;
String getNextId() {
Time now = System.getTime();
if (lastTime == now)
counter ++;
else
counter = 0;
return now+counter;
}
이것은 내가 메소드를 더 자주 호출했을 때에도 새로운 ID를 얻을 것을 보장 할 것입니다. getTime()
변화.
다른 팁
단일 코어 프로세서의 한 컴퓨터에서 실행하면 논리가 나에게 건전한 것 같습니다. 그러나 연속 통화를 위해 멀티 코어 프로세서에 대해 동일하게 유지되는지 모르겠습니다. 그러나 생성 된 숫자는 기계에서 고유하지 않을 것입니다.
호기심으로 인해 안내를 사용하지 않는 이유가 있습니까?
또는 생성 된 ID를 목록에 보관하는 것을 고려하고 있기 때문에 비교하는 이유는 무엇입니까? 스토리지가 옵션이라고 제안하기 때문에 마지막으로 사용 된 숫자를 저장하고 매번 사용하는 경우 ... 원하는 경우 매일 날짜를 저장하고 카운터를 재설정 할 수도 있습니다.
나는 상식에도 불구하고 변화하지 않은 빠른 루프에서 시간에 문제가있었습니다.
카운터 값을 여분의 몇 자리 (증분이 아닌)로 추가하고 다시 시작하거나 9999 이후에 재설정하면 모든 것을 불가능하게 만들기에 충분히 숨겨야합니다 (유명한 마지막 단어).
그런 다음 형식은 ttttttoooo입니다. 여기서 t는 시간 그림이고 O 4 자리 오프셋입니다.
AARON : 귀하의 의견에 감사드립니다. 귀하의 접근 방식을 사용하여 내가 원하는 것을 얻었습니다.
__forceinline bool GetUniqueIDEx(char caUID[MAX_STRING_LENGTH])
{
//Logic: Add HHMMSSmmm with 3 bytes counter.
//Guarantees a unique number for a calendar date,
//that in a single milli second band (0 to 999) the three bytes
//of counter would always be unique.
//1. Get system time, and use
bool bStatus = false;
try
{
GetLocalTime(&localtime);//Get local time, so that we may pull out HHMMSSmmm
char cNT[MAX_STRING_LENGTH];//new time.
memset(cNT, '\0', sizeof(cNT));
if(m_nCounter> MAX_COUNTER_LIMIT)
{
m_nCounter= 0;
}
sprintf(cNT, "%03d", ++m_nCounter);
//Prepare unique id
sprintf(caUID, "%02d%02d%02d%03d%s",
localtime.wHour,
localtime.wMinute,
localtime.wSecond,
localtime.wMilliseconds,
cNT);
bStatus = true;
}
catch(...)
{
//Couldnt prepare. There was some problem.
bStatus = false;
}
return bStatus;
}
자정 이후 몇 초와 카운터를 사용합니다. 이렇게하면 초당 최대 100 만 명을 히트합니다. 꽤 독특해야합니다. 위의 Aaron의 코드를 사용하면 문자열을 다음과 같이 포맷합니다.
sprintf(idstr, "%05d%07d", secs_since_midnight, counter);
물론, 나는 또한 당신이 실제로 인쇄 가능한 캐릭터 (및 월/일이 아닌 연도 등)에 카운터를 크램링하고 싶을 때 Base-36 (ITOA를 통해)을 사용하는 것을 확고한 신자입니다).
귀하의 프로세스가 작은 성능 문제를 희생하고 논리를 단순하게 유지할 수 있는지 확실하지 않습니다.
두 통화 사이에서 프로세스를 1 밀리 초 동안 잠을 자면 HHMMSSMMM 형식 자체가있는 고유 번호를 보장 할 수 있습니다. 이런 식으로 연결 부분과 고유성을 두 번 확인하기 위해 유지 해야하는 목록을 제거 할 수 있습니다.
Manikanthan Velayutham // Big Think에 프로그램되었습니다