Pergunta

Eu queria um número que permaneceria único para um dia (24 horas). Segue-se o código que eu vim com; Eu estava pensando sobre suas falácias / possíveis riscos; 'Eu acredito' isso garante um número exclusivo de 12 dígitos para a pelo menos dia.

Logic é obter a data / hora atual (hhmmssmmm) e concat os primeiros quatro bytes de consulta resultado contador de desempenho.

__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 seguir é a saída que eu recebo:

Ú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] Milissegundo mudado, 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] Milissegundo mudado, 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] Milissegundo mudado, 125 Único: [1259071402495] Único: [1259071402497] Único: [1259071402498] Único: [1259071402499] Único: [1259071402500] Único: [1259071402502] Único: [1259071402503] Único: [1259071402504] Único: [1259071402505] Único: [1259071402507]

Agora estou pensando em manter os IDs gerados em uma lista, e comparar o novo gerado com as existentes na lista. Se já existir na lista, em seguida, bem, eu certamente pode ignorar o número e gerar outro, mas certamente e claramente essa lógica seria um fracasso.

Gostaria de receber seus comentários / sugestões / atualizações / etc.

Graças JT.

Foi útil?

Solução

A minha solução era fazer com que a hora do sistema e adicionar um contador para que (código pseudo):

static int counter = 0;
static Time lastTime;

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

Isso garantiria que eu obter um novo ID, mesmo quando eu chamei o método mais frequentemente do que mudanças getTime().

Outras dicas

A lógica parece som para mim se você estiver executando-o de uma máquina em um processador single-core. Eu não sei se o mesmo vale para um processador multi-core para chamadas sucessivas, no entanto. Os números gerados definitivamente não vai ser exclusivo em máquinas, no entanto.

A título de curiosidade, há uma razão que você não está usando GUIDs?

Ou desde que você está pensando em manter os IDs gerados em uma lista para comparar, porque você não pode criar um gerador? Desde que você sugere o armazenamento é uma opção, se você armazenar o último número utilizado e incrementá-la cada utilização ... Você pode até mesmo armazenar uma data e repor o contador a cada dia, se desejar.

Eu tive problemas com tempos de voltas rápidas onde eles não mudaram apesar de ser o senso comum que deve (você não tem nenhum controle sobre o sistema operacional para que você não pode assumir que o tempo muda a cada x milissegundos etc.)

Adicionando o valor do contador como um extra alguns dígitos (não como um incremento) e redefini-lo na reinicialização ou depois de 9999 deve esconder isso o suficiente para torná-lo quase impossível de acontecer (últimas palavras famosas).

formato é então TTTTTToooo onde T é a sua figura tempo e o seu 4 dígitos offset.

Aaron: Obrigado por seus comentários, eu usei sua abordagem para conseguir o que queria.

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

Eu usaria segundos desde a meia-noite e, em seguida, um contador. Isto dá-lhe até milhões sucessos dez por segundo. Deve ser bastante único. Usando o código de Aaron acima, você formatar a string como:

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

Claro, eu também sou um crente firme em usar base-36 (via itoa) quando você realmente quer para empinar um contador em poucos caracteres imprimíveis (e dia do ano, em vez de mês / dia, etc.)

Eu não tenho certeza se o seu processo pode sacrificar pequeno problema de desempenho e manter a lógica simples.

Podemos garantir número único com formato HHMMSSmmm si mesmo se você colocar o seu processo para dormir por 1 milissegundo entre duas chamadas. Por esta maneira você pode eliminar a parte concatenação e também a lista que você tem de manter a dupla verificação da unicidade.

Manikanthan Velayutham // programados para pensar BIG

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top