Python docs声明uuid1使用当前时间来形成uuid值。但我找不到确保UUID1顺序的引用。
>>> import uuid
>>> u1 = uuid.uuid1()
>>> u2 = uuid.uuid1()
>>> u1 < u2
True
>>>
答案 0 :(得分:15)
但并非总是如此:
>>> def test(n):
... old = uuid.uuid1()
... print old
... for x in range(n):
... new = uuid.uuid1()
... if old >= new:
... print "OOops"
... break
... old = new
... print new
>>> test(1000000)
fd4ae687-3619-11e1-8801-c82a1450e52f
OOops
00000035-361a-11e1-bc9f-c82a1450e52f
答案 1 :(得分:9)
不,标准UUID 不意味着顺序。
显然,一些尝试是使用GUID(Microsoft在UUID上的扭曲)使它们顺序地帮助提高某些数据库场景中的性能。但顺序不是UUID的意图。 http://en.wikipedia.org/wiki/Globally_unique_identifier
不,在标准UUID中,MAC地址不是第一个组件。 MAC地址是版本1 UUID中的 last 组件。 http://en.wikipedia.org/wiki/Universally_unique_identifier
各种版本的UUID旨在相互兼容。因此,期望您始终拥有版本1 UUID可能是不合理的。其他程序员可能会使用其他版本。
答案 2 :(得分:5)
从主机ID,序列号和当前时间生成UUID。如果未给出node,则使用getnode()来获取硬件地址。如果给出clock_seq,则将其用作序列号;否则选择随机的14位序列号。
由此,我推断MAC地址是第一个,然后是(可能是随机的)序列号,然后是当前时间。因此,即使对于由同一台机器/进程生成的UUID,我也不希望保证这些单调增加。
答案 3 :(得分:4)
我在http://doanduyhai.wordpress.com/2012/07/05/apache-cassandra-tricks-and-traps/
中偶然发现了Cassandra / Python中可能的答案Cassandra在所有原始类型中提供对类型1(基于时间和服务器)和类型4(随机)的UUID值的支持。
UUID(Unique Universal IDentifier)的主要用途是在潜在的分布式环境中获取真正唯一的标识符。
Cassandra确实支持版本1 UUID。它通过组合计算机的MAC地址和自公历开始以来100纳秒间隔的数量为您提供唯一标识符。
正如您所看到的,精度仅为100纳秒,但幸运的是它与时钟序列混合以增加随机性。此外,MAC地址也用于计算UUID,因此您不太可能在一台机器上遇到冲突,除非您需要处理非常大量的数据(不要忘记,不是每个人都是Twitter或Facebook)
UUID最重要的用例之一,特别是TimeUUID,是将其用作列密钥。由于Cassandra列键已排序,我们可以利用此功能为列族提供自然排序。
Hector客户端提供的默认com.eaio.uuid.UUID的问题在于它不易使用。作为ID,您可能需要将此值从服务器带到视图层,这就是问题所在。
基本上,com.eaio.uuid.UUID会覆盖toString()以提供UUID的String表示形式。但是,此字符串格式无法按字典顺序排序...
以下是连续生成的一些TimeUUID:
8e4cab00-c481-11e1-983b-20cf309ff6dc at some t1
2b6e3160-c482-11e1-addf-20cf309ff6dc at some t2 with t2 > t1
“2b6e3160-c482-11e1-addf-20cf309ff6dc”.compareTo(“8e4cab00-c481-11e1-983b-20cf309ff6dc”)
给出-6意味着“2b6e3160-c482-11e1-addf-20cf309ff6dc”少于/之前“8e4cab00-c481-11e1-983b-20cf309ff6dc”< / strong>这是不正确的。
TimeUUID的当前文本显示按以下方式分割:
time_low – time_mid – time_high_and_version – variant_and_sequence – node
如果我们从time_high_and_version开始重新排序,我们可以按字典顺序对其进行排序:
time_high_and_version – time_mid – time_low – variant_and_sequence – node
实用程序类如下:
public static String reorderTimeUUId(String originalTimeUUID)
{
StringTokenizer tokens = new StringTokenizer(originalTimeUUID, "-");
if (tokens.countTokens() == 5)
{
String time_low = tokens.nextToken();
String time_mid = tokens.nextToken();
String time_high_and_version = tokens.nextToken();
String variant_and_sequence = tokens.nextToken();
String node = tokens.nextToken();
return time_high_and_version + '-' + time_mid + '-' + time_low + '-' + variant_and_sequence + '-' + node;
}
return originalTimeUUID;
}
TimeUUID成为:
11e1-c481-8e4cab00-983b-20cf309ff6dc
11e1-c482-2b6e3160-addf-20cf309ff6dc
现在我们得到:
"11e1-c481-8e4cab00-983b-20cf309ff6dc".compareTo("11e1-c482-2b6e3160-addf-20cf309ff6dc") = -1
答案 4 :(得分:0)
无参数地使用uuid.uuid1()
会产生非顺序的结果(see answer by @basil-bourque),但是如果您设置clock_seq
或node
的参数,则可以很容易地将其设为连续的(因为在此情况下案例uuid1
使用python实现,该实现保证unique and sequential timestamp
在当前进程中属于UUID的一部分):
import time
from uuid import uuid1, getnode
from random import getrandbits
_my_clock_seq = getrandbits(14)
_my_node = getnode()
def sequential_uuid(node=None):
return uuid1(node=node, clock_seq=_my_clock_seq)
def alt_sequential_uuid(clock_seq=None):
return uuid1(node=_my_node, clock_seq=clock_seq)
if __name__ == '__main__':
from itertools import count
old_n = uuid1() # "Native"
old_s = sequential_uuid() # Sequential
native_conflict_index = None
t_0 = time.time()
for x in count():
new_n = uuid1()
new_s = sequential_uuid()
if old_n > new_n and not native_conflict_index:
native_conflict_index = x
if old_s >= new_s:
print("OOops: non-sequential results for `sequential_uuid()`")
break
if (x >= 10*0x3fff and time.time() - t_0 > 30) or (native_conflict_index and x > 2*native_conflict_index):
print('No issues for `sequential_uuid()`')
break
old_n = new_n
old_s = new_s
print(f'Conflicts for `uuid.uuid1()`: {bool(native_conflict_index)}')
print(f"Tries: {x}")
但是,如果您正在同一台计算机上运行一些并行进程,则:
node
(默认为uuid.get_node()
)对于所有进程都是相同的; clock_seq
在某些过程中具有相同可能性的可能性很小(机会为1/16384)那可能导致冲突!这是使用时的普遍关注
除非您可以从Python3.7中访问SafeUUID,否则uuid.uuid1
可以在同一台计算机上并行处理。
如果您还确保为运行此代码的每个并行进程也将node
设置为唯一值,那么就不会发生冲突。
即使您使用的是SafeUUID,并且设置了唯一的node
,如果它们是在不同的进程中生成的,仍然可以具有非顺序ID。
如果可以接受一些与锁相关的开销,那么您可以将clock_seq
存储在某些外部原子存储中(例如,存储在"locked"文件中),并在每次调用时对其进行递增:这允许具有相同的值在所有并行进程上用于node
,并且还将使id-s顺序。对于所有并行流程都是使用multiprocessing
创建的子流程的情况:可以使用multiprocessing.Value
clock_seq