Dai*_*ner 31 c++ random performance c++11
C++11 通过该库支持伪随机数生成<random>。
我看过多本书籍,其中提到持续构建和销毁std::random_device, std::uniform_int_distribution<>,std::uniform_real_distribution<>对象的成本非常高,并且他们建议在应用程序中保留这些对象的单个副本。
为什么创建/销毁这些对象的成本很高?这里的贵到底是什么意思呢?就执行速度、可执行文件大小或其他方面而言,它是否昂贵?
有人可以提供一些解释吗?
Ted*_*gmo 32
std::random_device创建起来可能很昂贵。它可能会打开一个向其提供数据的设备,这需要一些时间。调用起来也可能很昂贵,因为它需要熵来提供真正的随机数,而不是伪随机数。uniform_int_distribution创造从来都不是昂贵的。它的设计目的是为了便宜。但它确实有内部状态,因此在极端情况下,如果可以的话,请在调用之间保持相同的分布。default_random_engine或mt19937,通常创建成本较低,但播种成本较高。这有多昂贵很大程度上取决于它们内部保存的状态的大小以及播种程序是什么。例如,std::mersenne_twister_engine标准库中的 保持“大”(倾向于“巨大”)状态,这使得创建成本非常昂贵。优点:
random_device并调用它一次来播种一个PRNG。因此,需要进行一项昂贵的创建和调用,random_device以及一项昂贵的 PRNG 播种。Hom*_*512 23
简短的答案是:这取决于系统和库的实现
在低质量的实现中,例如 9.2 之前的 MinGW,random_device只不过是一个多余的包装器std::rand()。我不知道这样的实现仍然存在,但有人可能会纠正我
在裸机系统上,例如嵌入式微控制器,random_device可以直接与硬件随机数生成器或相应的 CPU 功能交互。这可能需要也可能不需要昂贵的设置,例如配置硬件、打开通信通道或丢弃前 N 个样本
您很可能位于托管平台上,这意味着具有硬件抽象级别的现代操作系统。让我们在本文的其余部分考虑这种情况
random_device您的系统可能有一个真正的硬件随机数生成器,例如 TPM 模块可以充当其中之一。请参阅可信平台模块如何生成其真正的随机数?对此硬件的任何访问都必须通过操作系统,例如在 Windows 上,这可能是加密服务提供商 (CSP)。
或者您的 CPU 可能内置一些指令,例如 Intel 的rdrand和rdseed指令。在这种情况下,random_device直接映射到这些的 a 只需要发现它们是否可用并检查它们是否可操作。rdrand例如可以检测硬件故障,此时实现可以提供后备。请参阅Ivy Bridge 上 RDRAND 的耗尽特性是什么?
然而,由于这些功能可能不可用,因此操作系统通常提供熵池来生成随机数。如果这些硬件功能可用,您的操作系统可能会使用它们来为该池提供数据,或者在池耗尽时提供后备。您的标准库很可能只是通过特定于操作系统的 API 访问该池。
这就是random_device目前所有主流库实现中的内容:用于随机数生成的操作系统设施的访问点。那么这些的设置开销是多少?
传统的 POSIX (UNIX) 操作系统通过伪设备/dev/random和提供随机数/dev/urandom。因此设置成本与打开和关闭该文件相同。我想这就是你的书所指的
由于这个 API 有一些缺点,新的 API 已经出现,例如 Linux 的getrandom. 这个不会有任何设置成本,但如果内核不支持它,它可能会失败,此时一个好的库可能会/dev/urandom再次尝试
Windows 库可能会通过其加密 API。因此,无论是旧的 CSP APICryptGenRandom还是新的BCryptGenRandom. 两者都需要服务或算法提供者的句柄。所以这可能类似于/dev/urandom方法
在所有这些情况下,您将需要至少一个系统调用来访问 RNG,并且这些调用比正常的函数调用要慢得多。请参阅系统调用开销,甚至rdrand每条指令的指令大约有 150 个周期。请参阅Ivy Bridge 上 RDRAND 指令的延迟和吞吐量是多少?或者更糟糕的是,查看各种编译器上的 RDRAND 和 RDSEED 内在函数?
库(或用户)可能会试图通过缓冲大量随机字节(例如使用缓冲文件 I/O)来减少系统调用的数量。random_device假设这会丢弃缓冲区,这又会让打开和关闭变得不明智。
此外,操作系统熵池的大小有限,可能会耗尽,这可能会导致整个系统受到影响(通过使用低于标准的随机数或阻塞直到熵再次可用)。这和缓慢的性能意味着您通常不应该random_device直接将其输入uniform_int_distribution或类似的东西。相反,使用它来初始化伪随机数生成器。
当然这也有例外。例如,如果您的程序在整个运行过程中只需要 64 个随机字节,那么绘制 2.5 kiB 随机状态来初始化梅森扭曲器将是愚蠢的。或者,如果您需要尽可能好的熵,例如生成加密密钥,那么请务必使用它(或者更好的是,为此使用库;永远不要重新发明加密!)
| 归档时间: |
|
| 查看次数: |
2637 次 |
| 最近记录: |