0

我想要一个在一天(24 小时)内保持唯一的号码。以下是我想出的代码;我想知道它的谬误/可能的风险;“我相信”这保证了至少一天的 12 位唯一编号。

逻辑是获取当前日期/时间(hhmmssmmm)并连接查询性能计数器结果的前四个字节。

__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 4627431] 唯一:[23] 唯一:[12590] [125907 462233] 唯一:[125907 462234] 唯一:[125907 462235] 唯一:[125907 462237] 唯一:[125907 462238] 唯一:[125907 462239] 唯一:[125907 462240] 唯一:[1259125] 唯一:[1259125] 462243] 唯一:[125907 462244] 唯一:[125907 462245] 唯一:[125907 462246] 唯一:[125907 462247] 唯一:[125907 462248] 唯一:[125907 462249] 唯一:[1225907 460272562]唯一:[125907 462253] 唯一:[125907 462254] 唯一:[125907 462255] 唯一:[125907 462256] 唯一:[125907 462257] 唯一:[125907 462258] 毫秒改变,46 唯一:[125907 62027261] 622262] 唯一:[125907 622263] 唯一:[125907 622264] 唯一:[125907 622265] 唯一:[125907 622267] 唯一:[125907 622268] 唯一:[125907 622269] 唯一:[125907 622270] 唯一:[125907 622271] 唯一:[125907 622273] 唯一:[125907 622274] 唯一:[1259125]6275] 622276] 唯一:[125907 622277] 唯一:[125907 622278] 唯一:[125907 622279] 唯一:[125907 622281] 唯一:[125907 622282] 唯一:[125907 622283] 唯一:[1225907 62027264]独特:[125907 622286] 独特:[125907 622288] 独特:[125907 622289] 独特:[125907 622290] 独特:[125907 622291] 独特:[125907 622292] 独特:[125907 6227293] 独特:[12590] 独特:[12590] [125907 622296] 唯一:[125907 622297] 唯一:[125907 622298] 唯一:[125907 622299] 唯一:[125907 622300] 唯一:[125907 622301] 唯一:[125907 622302] 唯一:[1259125] 唯一:[125912] 622305] 唯一:[125907 622306] 毫秒更改,62 唯一:[125907 782308] 唯一:[125907 782310] 唯一:[125907 782311] 唯一:[125907 782312] 唯一:[125907 782313] 唯一:[125907 782314] 唯一:[125907 782316] 唯一:[125907 782317] 唯一:[1259125] 唯一:[125912] 782319]毫秒改变,125个独特:[1259071402495]唯一:[1259071402497]唯一:[1259071402498]唯一:[1259071402499]独特:[1259071402500]独特:[1259071402502]独特:[1259071402503]独特:[1259071402504]独特:[1259071402504 ] 唯一:[1259071402507][1259071402504] 唯一:[1259071402505] 唯一:[1259071402507][1259071402504] 唯一:[1259071402505] 唯一:[1259071402507]

现在我正在考虑将生成的 ID 保存在一个列表中,并将新生成的 ID 与列表中的现有 ID 进行比较。如果它已经存在于列表中,那么我当然可以跳过这个数字并生成另一个,但当然很明显这个逻辑会失败。

非常感谢您的意见/建议/更新/等。

谢谢JT。

4

6 回答 6

1

如果您是在单核处理器上的一台机器上运行它,那么逻辑对我来说似乎是合理的。但是,我不知道对于连续调用的多核处理器是否同样适用。但是,生成的数字在机器之间肯定不会是唯一的。

出于好奇,您是否有理由不使用 GUID?

或者,既然您正在考虑将生成的 ID 保存在一个列表中进行比较,为什么不能创建一个生成器?由于您建议存储是一种选择,如果您存储最后使用的数字并在每次使用时增加它......您甚至可以存储日期并根据需要每天重置计数器。

于 2009-03-25T08:39:47.080 回答
1

我的解决方案是获取系统时间并为其添加一个计数器(伪代码):

static int counter = 0;
static Time lastTime;

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

这将保证即使我更频繁地调用该方法而不是getTime()更改时,我也会获得一个新 ID。

于 2009-03-25T08:43:12.283 回答
0

我遇到了快速循环中的时间问题,尽管它们应该是常识,但它们没有改变(你无法控制操作系统,所以你不能假设时间每 x 毫秒改变一次等)

将计数器值添加为额外的几位数字(而不是增量)并在重新启动时或在 9999 之后将其重置应该足以隐藏这一点,使其几乎不可能发生(著名的遗言)。

然后格式是 TTTTTToooo,其中 T 是您的时间数字和 o 您的 4 位偏移量。

于 2009-03-25T12:55:33.627 回答
0

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;
}
于 2009-04-03T05:34:10.040 回答
0

我会使用午夜后的秒数,然后使用计数器。这可以为您提供高达每秒一千万次点击。应该很独特。使用上面 Aaron 的代码,您可以将字符串格式化为:

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

当然,当您真的想将计数器塞入几个可打印字符(以及一年中的某天而不是月/日等)时,我也坚信使用 base-36(通过 itoa)

于 2009-04-27T02:27:16.690 回答
0

我不确定您的流程是否可以牺牲微小的性能问题并保持逻辑简单。

如果您在两次调用之间让您的进程休眠 1 毫秒,我们可以保证 HHMMSSmmm 格式本身的唯一编号。通过这种方式,您可以消除连接部分以及您必须维护的列表以仔细检查唯一性。

Manikanthan Velayutham // 编程思考大

于 2009-11-11T18:17:51.940 回答