我需要生成大量的UUID。如果我没有rg
静态,那么每次默认构建它都需要很长时间。如果我把它变成静态会有什么问题,它会不会影响uuids的独特性?
有没有更好的方法呢?
using namespace boost::uuids;
uuid generateUUID() {
static random_generator rg; // here
return rg();
}
void someFunction() {
for (int i = 0; i < 1000000; ++i) {
uuid id = generateUUID();
// use id
}
}
答案 0 :(得分:1)
我需要生成大量的UUID。如果我不让rg静态,那么每次默认构建它都需要很多时间。如果我把它变成静态会有什么不对吗,无论如何都会伤害uuids的独特性吗?
不,那很好......
有没有更好的方法呢?
...也许,这取决于您将需要的迭代次数。
你看到功能范围内的静态对象的(次要)问题在于标准的措辞,它规定:
a)对象是第一次代码流过语句
时构造的b)这种结构必须是线程安全的。
实际上,这意味着generateUUID()
中的代码必须测试它是否已经构造了对象。这涉及内存提取和条件分支。
这是在apple clang 7.0上使用-O3:
编译时函数的汇编代码输出__Z12generateUUIDv: ## @_Z12generateUUIDv
Lfunc_begin0:
.cfi_startproc
.cfi_personality 155, ___gxx_personality_v0
.cfi_lsda 16, Lexception0
## BB#0:
pushq %rbp
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp5:
.cfi_def_cfa_register %rbp
pushq %rbx
subq $24, %rsp
Ltmp6:
.cfi_offset %rbx, -24
movb __ZGVZ12generateUUIDvE2rg(%rip), %al ## MEMORY FETCH
testb %al, %al ## TEST
jne LBB0_4 ## CONDITIONAL BRANCH
## BB#1:
leaq __ZGVZ12generateUUIDvE2rg(%rip), %rdi ## another check in case
callq ___cxa_guard_acquire ## 2+ threads are racing
testl %eax, %eax
je LBB0_4
... ## object constructed here
这是必要的,因为任何人都可以调用该函数。优化者无法知道施工是否已经发生过。因此,我们不再需要3条额外的指令,因为我们选择了在需要时构建对象的奢侈品。
这意味着如果您处于紧密循环中,可能希望避免所有这些冗余测试。
问题是,创建生成器的成本与300万条指令执行的成本和(希望)正确预测的分支成本是什么?
在大量迭代中,以下代码实际上变得更有效(如果这对您来说真的很重要):
void someFunction() {
// one generator used for the duration of the function
random_generator rg;
for (int i = 0; i < 1000000; ++i) {
uuid id = rg();
// use id
}
}
最有效地使用静态生成器是这样的:
using namespace boost::uuids;
static random_generator rg; // constructed at some point before main() is called
// we no longer require flag tests
void someFunction() {
for (int i = 0; i < 1000000; ++i) {
uuid id = rg();
// use id
}
}
然而,这稍微不方便,因为我们现在必须注意,在调用rg
之前不会使用main()
(除非您仅在定义它的同一编译单元中使用它)。
答案 1 :(得分:0)
不,这没有问题。