Pregunta

Yo quería un número que permanecería único para un día (24 horas). El siguiente es el código que se me ocurrió; Me preguntaba sobre sus falacias / posibles riesgos; 'Yo creo' esto garantiza un número único de 12 dígitos para un día al menos.

La lógica es para obtener la fecha / hora actual (hhmmssmmm) y concat los primeros cuatro bytes del resultado del contador rendimiento de las consultas.

__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;
}

A continuación se muestra la salida que me sale:

Único: [125907 462224] Único: [125907 462225] Único: [125907 462226] Único: [125907 462227] Único: [125907 462228] Único: [125907 462230] Único: [125907 462231] Único: [125907 462232] Único: [125907 462233] Único: [125907 462234] Único: [125907 462235] Único: [125907 462237] Único: [125907 462238] Único: [125907 462239] Único: [125907 462240] Único: [125907 462241] Único: [125907 462243] Único: [125907 462244] Único: [125907 462245] Único: [125907 462246] Único: [125907 462247] Único: [125907 462248] Único: [125907 462249] Único: [125907 462251] Único: [125907 462252] Único: [125907 462253] Único: [125907 462254] Único: [125907 462255] Único: [125907 462256] Único: [125907 462257] Único: [125907 462258] Milisegundo cambió, 46 Único: [125907 622261] Único: [125907 622262] Único: [125907 622263] Único: [125907 622264] Único: [125907 622265] Único: [125907 622267] Único: [125907 622268] Único: [125907 622269] Único: [125907 622270] Único: [125907 622271] Único: [125907 622273] Único: [125907 622274] Único: [125907 622275] Único: [125907 622276] Único: [125907 622277] Único: [125907 622278] Único: [125907 622279] Único: [125907 622281] Único: [125907 622282] Único: [125907 622283] Único: [125907 622284] Único: [125907 622285] Único: [125907 622286] Único: [125907 622288] Único: [125907 622289] Único: [125907 622290] Único: [125907 622291] Único: [125907 622292] Único: [125907 622293] Único: [125907 622295] Único: [125907 622296] Único: [125907 622297] Único: [125907 622298] Único: [125907 622299] Único: [125907 622300] Único: [125907 622301] Único: [125907 622302] Único: [125907 622304] Único: [125907 622305] Único: [125907 622306] Milisegundo cambió, 62 Único: [125907 782308] Único: [125907 782310] Único: [125907 782311] Único: [125907 782312] Único: [125907 782313] Único: [125907 782314] Único: [125907 782316] Único: [125907 782317] Único: [125907 782318] Único: [125907 782319] Milisegundo cambió, 125 Único: [1259071402495] Único: [1259071402497] Único: [1259071402498] Único: [1259071402499] Único: [1259071402500] Único: [1259071402502] Único: [1259071402503] Único: [1259071402504] Único: [1259071402505] Único: [1259071402507]

Ahora pienso en mantener los identificadores generados en una lista, y comparar la nueva generada con los existentes en la lista. Si ya existe en la lista, a continuación, así que puedo desde luego saltar el número y generar otro, pero sin duda y claramente esta lógica sería un fracaso.

aprecia sus observaciones / propuestas / actualizaciones / etc.

Gracias JT.

¿Fue útil?

Solución

Mi solución era conseguir la hora del sistema e agregar un contador a la (pseudo código):

static int counter = 0;
static Time lastTime;

String getNextId() {
    Time now = System.getTime();
    if (lastTime == now)
        counter ++;
    else
        counter = 0;
    return now+counter;
}

Esto garantizaría que me gustaría conseguir una nueva identificación, incluso cuando me llamó el método más a menudo que los cambios getTime().

Otros consejos

La lógica parece sonar a mí si usted lo está funcionando de una máquina en un procesador de un solo núcleo. No sé si es lo mismo vale para un procesador multi-núcleo para las llamadas sucesivas, sin embargo. Los números generados definitivamente no van a ser únicos en máquinas, sin embargo.

Por curiosidad, ¿hay alguna razón usted no está usando GUID?

O ya está pensando en mantener los identificadores generados en una lista para comparar, por qué no se puede crear un generador? Dado que usted sugiere almacenamiento es una opción, si almacena el último número e increméntelo cada uso ... Incluso puede almacenar una fecha y restablecer el contador de todos los días si así lo desea.

he tenido problemas con los tiempos en los bucles rápidos en los que no han cambiado a pesar de ser de sentido común que debe (usted no tiene ningún control sobre el sistema operativo por lo que no se puede asumir que el tiempo cambia cada x milisegundos, etc.)

Agregar el valor del contador como un par de dígitos adicionales (no como un incremento) y ponerlo a cero en el reinicio o después de 9999 debe ocultar esto suficiente para que sea casi imposible que suceda (famosas últimas palabras).

formato es entonces TTTTTToooo donde T es el tiempo y la figura 4 dígitos o su desplazamiento.

Aaron: Gracias por sus comentarios, que utiliza su enfoque para conseguir lo que quería.

__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;
}

Me gustaría utilizar segundos desde la medianoche y después de un mostrador. Esto le da un máximo de diez millones de visitas por segundo. Debe ser bastante único. Utilizando el código de Aaron anteriormente, da formato a la cadena como:

sprintf(idstr, "%05d%07d", secs_since_midnight, counter);

Por supuesto, también soy un firme creyente en el uso de la base-36 (vía itoa) cuando realmente quiere meter un contador en unos pocos caracteres imprimibles (y el día del año en lugar de mes / día, etc.)

No estoy seguro de si el proceso puede sacrificar problema de rendimiento diminuta y mantener la lógica simple.

Podemos garantizar número único con el formato HHMMSSmmm sí mismo si usted pone su proceso de dormir durante 1 milisegundo entre dos llamadas. De esta manera se puede eliminar la parte de concatenación y también la lista de lo que tiene que mantener a duplicar comprobar la singularidad.

Manikanthan Velayutham // programado para pensar en grande

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top