为什么随机设备创建昂贵?

阿米尔

<random>C++11 支持通过库生成伪随机数。

我看过多本书籍,其中提到继续构造和销毁std::random_device,对象非常昂贵std::uniform_int_distribution<>std::uniform_real_distribution<>他们建议在应用程序中保留这些对象的单个副本。

为什么创建/销毁这些对象很昂贵?这里的贵到底是什么意思它在执行速度可执行文件大小或其他方面是否昂贵?

有人可以提供一些解释吗?

荷马512

简短的回答是:这取决于系统和库的实现

标准库的类型

  • 在一个童话世界中,你拥有可以想象到的最糟糕的标准库实现,random_device只不过是一个多余的包装器std::rand()我不知道这样的实现,但有人可能会纠正我

  • 在裸机系统上,例如嵌入式微控制器,random_device可以直接与硬件随机数生成器或相应的 CPU 功能进行交互。这可能需要也可能不需要昂贵的设置,例如配置硬件、打开通信通道或丢弃前 N 个样本

  • 您很可能在托管平台上,这意味着具有硬件抽象级别的现代操作系统。让我们在这篇文章的其余部分考虑这个案例

种类random_device

您的系统可能有一个真正的硬件随机数生成器,例如 TPM 模块可以充当一个。请参阅可信平台模块如何生成其真正的随机数?对该硬件的任何访问都必须通过操作系统,例如在 Windows 上,这可能由加密服务提供商 (CSP)进行。

或者你的 CPU 可能有一些内置的,比如 Intel 的rdrandrdseed指令。在这种情况下random_device,直接映射到这些的 a 只需发现它们可用并检查它们是否可操作。rdrand例如,可以检测到硬件故障,此时实现可以提供回退。请参阅常春藤桥上 RDRAND 的耗尽特征是什么?

但是,由于这些功能可能不可用,操作系统通常会提供一个熵池来生成随机数。如果这些硬件功能可用,您的操作系统可能会使用它们来提供此池或在池耗尽时提供回退。您的标准库很可能只是通过特定于操作系统的 API 访问此池。那么这些的设置开销是多少?

系统 API

  • 传统的 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直接输入到 auniform_int_distribution或类似的东西中。而是使用它来初始化伪随机数生成器。

当然这也有例外。例如,如果您的程序在其整个运行过程中只需要 64 个随机字节,那么绘制 2.5 kiB 随机状态来初始化 mersenne twister 将是愚蠢的。或者,如果您需要尽可能好的熵,例如生成加密密钥,那么无论如何,使用它(或者更好的是,为此使用库;永远不要重新发明加密!

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章