计算两个缓冲区之间的差异似乎太慢

2023-11-21

我的问题

我有2个adjacent相同大小的字节缓冲区(每个大约 20 MB)。我只是想数一下它们之间的差异。

我的问题

该循环在具有 3600MT RAM 的 4.8GHz Intel I7 9700K 上运行需要多长时间?

我们如何计算最大理论速度?

我尝试过的

uint64_t compareFunction(const char *const __restrict buffer, const uint64_t commonSize)
{
    uint64_t diffFound = 0;

    for(uint64_t byte = 0; byte < commonSize; ++byte)
        diffFound += static_cast<uint64_t>(buffer[byte] != buffer[byte + commonSize]);

    return diffFound;
}

在我的电脑(9700K 4.8Ghz RAM 3600 Windows 10 Clang 14.0.6 -O3 MinGW)上需要 11 毫秒,我觉得它太慢了,而且我错过了一些东西。

CPU 读取 40MB 的时间应该少于 2 毫秒(我的 RAM 带宽在 20 到 30GB/s 之间)

我不知道如何计算执行一次迭代所需的周期(特别是因为现在的 CPU 是超标量的)。如果我假设每个操作有 1 个周期,并且如果我没有搞乱计数,那么每次迭代应该有 10 个操作 -> 2 亿个操作 -> 在 4.8 Ghz 下只有一个执行单元 -> 40ms。显然我在如何计算每个循环的周期数上是错误的。

有趣的事实:我在 Linux PopOS GCC 11.2 -O3 上尝试过,它的运行时间为 4.5 毫秒。为什么会有这样的差异?

以下是 clang 生成的反汇编向量和标量:

compareFunction(char const*, unsigned long): # @compareFunction(char const*, unsigned long)
        test    rsi, rsi
        je      .LBB0_1
        lea     r8, [rdi + rsi]
        neg     rsi
        xor     edx, edx
        xor     eax, eax
.LBB0_4:                                # =>This Inner Loop Header: Depth=1
        movzx   r9d, byte ptr [rdi + rdx]
        xor     ecx, ecx
        cmp     r9b, byte ptr [r8 + rdx]
        setne   cl
        add     rax, rcx
        add     rdx, 1
        mov     rcx, rsi
        add     rcx, rdx
        jne     .LBB0_4
        ret
.LBB0_1:
        xor     eax, eax
        ret

铿锵14 O3:

.LCPI0_0:
        .quad   1                               # 0x1
        .quad   1                               # 0x1
compareFunction(char const*, unsigned long):                # @compareFunction(char const*, unsigned long)
        test    rsi, rsi
        je      .LBB0_1
        cmp     rsi, 4
        jae     .LBB0_4
        xor     r9d, r9d
        xor     eax, eax
        jmp     .LBB0_11
.LBB0_1:
        xor     eax, eax
        ret
.LBB0_4:
        mov     r9, rsi
        and     r9, -4
        lea     rax, [r9 - 4]
        mov     r8, rax
        shr     r8, 2
        add     r8, 1
        test    rax, rax
        je      .LBB0_5
        mov     rdx, r8
        and     rdx, -2
        lea     r10, [rdi + 6]
        lea     r11, [rdi + rsi]
        add     r11, 6
        pxor    xmm0, xmm0
        xor     eax, eax
        pcmpeqd xmm2, xmm2
        movdqa  xmm3, xmmword ptr [rip + .LCPI0_0] # xmm3 = [1,1]
        pxor    xmm1, xmm1
.LBB0_7:                                # =>This Inner Loop Header: Depth=1
        movzx   ecx, word ptr [r10 + rax - 6]
        movd    xmm4, ecx
        movzx   ecx, word ptr [r10 + rax - 4]
        movd    xmm5, ecx
        movzx   ecx, word ptr [r11 + rax - 6]
        movd    xmm6, ecx
        pcmpeqb xmm6, xmm4
        movzx   ecx, word ptr [r11 + rax - 4]
        movd    xmm7, ecx
        pcmpeqb xmm7, xmm5
        pxor    xmm6, xmm2
        punpcklbw       xmm6, xmm6              # xmm6 = xmm6[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm4, xmm6, 212                 # xmm4 = xmm6[0,1,1,3,4,5,6,7]
        pshufd  xmm4, xmm4, 212                 # xmm4 = xmm4[0,1,1,3]
        pand    xmm4, xmm3
        paddq   xmm4, xmm0
        pxor    xmm7, xmm2
        punpcklbw       xmm7, xmm7              # xmm7 = xmm7[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm0, xmm7, 212                 # xmm0 = xmm7[0,1,1,3,4,5,6,7]
        pshufd  xmm5, xmm0, 212                 # xmm5 = xmm0[0,1,1,3]
        pand    xmm5, xmm3
        paddq   xmm5, xmm1
        movzx   ecx, word ptr [r10 + rax - 2]
        movd    xmm0, ecx
        movzx   ecx, word ptr [r10 + rax]
        movd    xmm1, ecx
        movzx   ecx, word ptr [r11 + rax - 2]
        movd    xmm6, ecx
        pcmpeqb xmm6, xmm0
        movzx   ecx, word ptr [r11 + rax]
        movd    xmm7, ecx
        pcmpeqb xmm7, xmm1
        pxor    xmm6, xmm2
        punpcklbw       xmm6, xmm6              # xmm6 = xmm6[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm0, xmm6, 212                 # xmm0 = xmm6[0,1,1,3,4,5,6,7]
        pshufd  xmm0, xmm0, 212                 # xmm0 = xmm0[0,1,1,3]
        pand    xmm0, xmm3
        paddq   xmm0, xmm4
        pxor    xmm7, xmm2
        punpcklbw       xmm7, xmm7              # xmm7 = xmm7[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm1, xmm7, 212                 # xmm1 = xmm7[0,1,1,3,4,5,6,7]
        pshufd  xmm1, xmm1, 212                 # xmm1 = xmm1[0,1,1,3]
        pand    xmm1, xmm3
        paddq   xmm1, xmm5
        add     rax, 8
        add     rdx, -2
        jne     .LBB0_7
        test    r8b, 1
        je      .LBB0_10
.LBB0_9:
        movzx   ecx, word ptr [rdi + rax]
        movd    xmm2, ecx
        movzx   ecx, word ptr [rdi + rax + 2]
        movd    xmm3, ecx
        add     rax, rsi
        movzx   ecx, word ptr [rdi + rax]
        movd    xmm4, ecx
        pcmpeqb xmm4, xmm2
        movzx   eax, word ptr [rdi + rax + 2]
        movd    xmm2, eax
        pcmpeqb xmm2, xmm3
        pcmpeqd xmm3, xmm3
        pxor    xmm4, xmm3
        punpcklbw       xmm4, xmm4              # xmm4 = xmm4[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm4, xmm4, 212                 # xmm4 = xmm4[0,1,1,3,4,5,6,7]
        pshufd  xmm4, xmm4, 212                 # xmm4 = xmm4[0,1,1,3]
        movdqa  xmm5, xmmword ptr [rip + .LCPI0_0] # xmm5 = [1,1]
        pand    xmm4, xmm5
        paddq   xmm0, xmm4
        pxor    xmm2, xmm3
        punpcklbw       xmm2, xmm2              # xmm2 = xmm2[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
        pshuflw xmm2, xmm2, 212                 # xmm2 = xmm2[0,1,1,3,4,5,6,7]
        pshufd  xmm2, xmm2, 212                 # xmm2 = xmm2[0,1,1,3]
        pand    xmm2, xmm5
        paddq   xmm1, xmm2
.LBB0_10:
        paddq   xmm0, xmm1
        pshufd  xmm1, xmm0, 238                 # xmm1 = xmm0[2,3,2,3]
        paddq   xmm1, xmm0
        movq    rax, xmm1
        cmp     r9, rsi
        je      .LBB0_13
.LBB0_11:
        lea     r8, [r9 + rsi]
        sub     rsi, r9
        add     r8, rdi
        add     rdi, r9
        xor     edx, edx
.LBB0_12:                               # =>This Inner Loop Header: Depth=1
        movzx   r9d, byte ptr [rdi + rdx]
        xor     ecx, ecx
        cmp     r9b, byte ptr [r8 + rdx]
        setne   cl
        add     rax, rcx
        add     rdx, 1
        cmp     rsi, rdx
        jne     .LBB0_12
.LBB0_13:
        ret
.LBB0_5:
        pxor    xmm0, xmm0
        xor     eax, eax
        pxor    xmm1, xmm1
        test    r8b, 1
        jne     .LBB0_9
        jmp     .LBB0_10

TLDR: Clang 代码如此缓慢的原因来自于糟糕的矢量化方法使端口 5 饱和(众所周知,这通常是一个问题)。 GCC 在这方面做得更好,但离高效还很远。人们可以使用 AVX-2 编写更快的基于块的代码,而不会使端口 5 饱和。


未矢量化的 Clang 代码分析

要了解发生了什么,最好从一个简单的示例开始。事实上,正如您所说,现代处理器是超标量的,因此理解这种架构上某些生成代码的速度并不容易。

Clang 生成的代码使用-O1优化标志是一个好的开始。这是您问题中提供的 GodBold 生成的热循环的代码:

(instructions)                                 (ports)

.LBB0_4:
        movzx   r9d, byte ptr [rdi + rdx]      p23
        xor     ecx, ecx                       p0156
        cmp     r9b, byte ptr [r8 + rdx]       p0156+p23
        setne   cl                             p06
        add     rax, rcx                       p0156
        add     rdx, 1                         p0156
        mov     rcx, rsi                       (optimized)
        add     rcx, rdx                       p0156
        jne     .LBB0_4                        p06

像 Coffee Lake 9700K 这样的现代处理器由两大部分组成:前端获取/解码指令(并将它们分成微指令,又名微指令)。uops),以及后端调度/执行它们。后端在许多上调度uopports他们每个人都可以执行一些具体指令集(例如,仅内存加载,或仅算术指令)。对于每条指令,我都放置了可以执行它们的端口。p0156+p23意味着指令被分成两个微指令:第一个可以由端口 0 或 1 或 5 或 6 执行,第二个可以由端口 2 或 3 执行。请注意,前端可以以某种方式优化代码所以不要为像这样的基本指令产生任何微指令mov在循环中(感谢一种称为寄存器重命名).

对于每次循环迭代,处理器需要从内存中读取 2 个值。像 9700K 这样的 Coffee Lake 处理器每个周期可以加载两个值,因此循环至少需要 1 个周期/迭代(假设加载r9d and r9b不会因使用同一部分的不同部分而发生冲突r964 位寄存器)。该处理器有一个微指令缓存,并且循环有很多指令,因此解码部分应该不成问题。也就是说,有 9 个微指令要执行,而处理器每个周期只能执行其中 6 个微指令,因此循环不能少于 1.5 个周期/迭代。更准确地说,端口 0、1、5 和 6 处于压力之下,因此即使假设处理器完美负载平衡微指令,也需要 2 个周期/迭代。这是一个乐观的执行时间下限,因为处理器可能无法完美地调度指令,并且有很多事情可能会出错(比如我没有看到的偷偷摸摸的隐藏依赖项)。频率为4.8GHz,最终执行时间至少为8.3ms。通过 3 个周期/迭代可以达到 12.5 ms(请注意,由于微指令到端口的调度,2.5 个周期/迭代是可能的)。

可以使用以下方法改进循环展开。事实上,仅仅执行循环而不是实际计算就需要大量指令。展开有助于提高有用指令的比例,从而更好地利用可用端口。尽管如此,2 个负载仍会阻止循环快于 1 个周期/迭代,即 4.2 ms。


矢量化 Clang 代码分析

Clang 生成的矢量化代码很复杂。人们可以尝试应用与之前的代码相同的分析,但这将是一项乏味的任务。

人们可以注意到,即使代码是矢量化的,负载未矢量化。这是一个问题,因为每个周期只能完成 2 次加载。也就是说,加载是通过两个连续的 char 值对执行的,因此与之前生成的代码相比,加载并不慢。

Clang 这样做是因为只有两个 64 位值可以放入 128 位 SSE 寄存器和一个 64 位寄存器中,并且它需要这样做,因为diffFound是一个 64 位整数。这8位到64位的转换是代码中最大的问题因为它需要多个 SSE 指令来进行转换。此外,由于 Coffee Lake 上有 3 个 SSE 整数单元,并且每个单元一次只能计算两个 64 位整数,因此一次只能计算 4 个整数。最后,Clang 只在每个 SSE 寄存器中放入 2 个值(并使用其中的 4 个值,以便每次循环迭代计算 8 个项目),因此人们应该期望代码运行速度快两倍以上(特别是由于 SSE 和循环展开),但情况并非如此,因为 SSE 端口比 ALU 端口少,并且类型转换所需的指令更多。简短地说,矢量化显然效率低下,但是在这种情况下 Clang 生成高效代码并不那么容易。尽管如此,由于每个循环有 28 个 SSE 指令和 3 个 SSE 整数单元计算 8 个项目,因此代码的计算部分应该需要大约28/3/8 ~= 1.2周期/项目与您可以观察到的相距甚远(这不是由于其他指令造成的,因为它们大多可以并行执行,因为它们大多可以在其他端口上调度)。

实际上,性能问题肯定来自端口5的饱和。事实上,该端口是唯一可以对 SIMD 寄存器项进行混洗的端口。因此,指令punpcklbw, pshuflw, pshufd甚至是movd只能在端口 5 上执行。这是 SIMD 代码的一个非常常见的问题。这是一个大问题,因为每个循环有 20 条指令,处理器甚至可能无法完美地使用它。这意味着代码应该至少需要 10.4 毫秒,这非常接近观察到的执行时间 (11 毫秒)。


矢量化 GCC 代码分析

与 Clang 相比,GCC 生成的代码实际上相当不错。首先,GCC 直接使用 SIMD 指令加载项目,这更加高效,因为每条指令(并通过迭代)计算 16 个项目:每次迭代只需要 2 个加载微指令,减少了端口 2 和 3 上的压力(1 个周期/迭代即,0.0625 周期/项目)。其次,GCC只使用了14punpckhwd指令,而每次迭代计算 16 个项目,减少端口 5 上的临界压力(0.875 个周期/项目)。第三,SIMD 寄存器几乎被完全使用,至少对于自pcmpeqb比较指令一次比较 16 个项目(而不是使用 Clang 比较 2 个项目)。其他指令如paddq很便宜(例如,paddq可以在 3 个 SSE 端口上进行调度),并且它们不会对执行时间产生太大影响。最后,这个版本应该仍然受到端口 5 的限制,但它应该比 Clang 版本快得多。事实上,我们应该预期执行时间将达到 1 个周期/项目(因为端口调度肯定不完美,并且内存负载可能会引入一些停顿周期)。这意味着执行时间为 4.2 毫秒。这与观察到的结果很接近。


更快的实施

GCC 的实施并不完美。

首先,它不使用您的处理器支持的 AVX2,因为the -mavx2未提供标志(或任何类似的标志,例如-march=native)。事实上,GCC 与其他主流编译器一样,默认情况下只使用 SSE2,以便与以前的架构兼容:SSE2 在所有 x86-64 处理器上可以安全使用,但不能在其他指令集(如 SSE3、SSSE3、SSE4.1、SSE4.2)上使用。 AVX、AVX2。有了这样的标志,GCC 应该能够生成内存绑定代码。

此外,理论上编译器可以执行多级求和归约。这个想法是使用大小为 1024 个项目(即 64x16 项目)的块在 8 位宽 SIMD 通道中累积比较结果。这是安全的,因为每个通道的值不能超过 64。为了避免溢出,累加值需要存储在更宽的 SIMD 通道中(例如 64 位通道)。通过这种策略,punpckhwd指令小 64 倍。这是一个很大的改进,因为它消除了端口 5 的饱和。即使仅使用 SSE2,此策略也应该足以生成内存限制代码。这是一个例子untested需要标志的代码-fopenmp-simd要有效率。

uint64_t compareFunction(const char *const __restrict buffer, const uint64_t commonSize)
{
    uint64_t byteChunk = 0;
    uint64_t diffFound = 0;

    if(commonSize >= 127)
    {
        for(; byteChunk < commonSize-127; byteChunk += 128)
        {
            uint8_t tmpDiffFound = 0;
            #pragma omp simd reduction(+:tmpDiffFound)
            for(uint64_t byte = byteChunk; byte < byteChunk + 128; ++byte)
                tmpDiffFound += buffer[byte] != buffer[byte + commonSize];
            diffFound += tmpDiffFound;
        }
    }

    for(uint64_t byte = byteChunk; byte < commonSize; ++byte)
        diffFound += buffer[byte] != buffer[byte + commonSize];

    return diffFound;
}

Both GCC and Clang生成相当高效的代码(虽然对于缓存中的数据拟合来说不是最佳的),尤其是 Clang。例如,以下是 Clang 使用 AVX2 生成的代码:

.LBB0_4:
        lea     r10, [rdx + 128]
        vmovdqu ymm2, ymmword ptr [r9 + rdx - 96]
        vmovdqu ymm3, ymmword ptr [r9 + rdx - 64]
        vmovdqu ymm4, ymmword ptr [r9 + rdx - 32]
        vpcmpeqb        ymm2, ymm2, ymmword ptr [rcx + rdx - 96]
        vpcmpeqb        ymm3, ymm3, ymmword ptr [rcx + rdx - 64]
        vpcmpeqb        ymm4, ymm4, ymmword ptr [rcx + rdx - 32]
        vmovdqu ymm5, ymmword ptr [r9 + rdx]
        vpaddb  ymm2, ymm4, ymm2
        vpcmpeqb        ymm4, ymm5, ymmword ptr [rcx + rdx]
        vpaddb  ymm3, ymm4, ymm3
        vpaddb  ymm2, ymm3, ymm2
        vpaddb  ymm2, ymm2, ymm0
        vextracti128    xmm3, ymm2, 1
        vpaddb  xmm2, xmm2, xmm3
        vpshufd xmm3, xmm2, 238
        vpaddb  xmm2, xmm2, xmm3
        vpsadbw xmm2, xmm2, xmm1
        vpextrb edx, xmm2, 0
        add     rax, rdx
        mov     rdx, r10
        cmp     r10, r8
        jb      .LBB0_4

所有负载均为 256 位 SIMD。的数量vpcmpeqb是最优的。的数量vpaddb是比较好的。还有一些其他指令,但它们显然不应该成为瓶颈。该循环每次迭代对 128 个项目进行操作,我预计每次迭代对于缓存中已有的数据只需要不到十几个周期(否则它应该完全受内存限制)。这意味着

请注意,生成顺序内存限制并不总是意味着 RAM 吞吐量将饱和。事实上,在一个核心上,有时会出现没有足够的并发来隐藏内存操作的延迟尽管它在您的处理器上应该没问题(就像在我的带有 2 个交错 3200 MHz DDR4 内存通道的 i5-9600KF 上一样)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算两个缓冲区之间的差异似乎太慢 的相关文章

  • PHP include():文件大小和性能

    一个没有经验的PHP问题 我有一个 PHP 脚本文件 我需要在不同页面的很多地方多次包含该文件 我可以选择将包含的文件分解为几个较小的文件 并根据需要包含这些文件 或者 我可以将它们全部保存在一个 PHP 文件中 我想知道在这种情况下使用较
  • 加载实体实例需要超过 1 秒

    我在EF中遇到了一件有趣的事情 如果我们使用基础实体获取子实体 则加载实体需要更多时间 我的模型看起来像这样 public abstract class BaseDocument public Guid Id get set public
  • 在二维平面中找到距离 P 点最近的 K 个点

    资料来源 亚马逊面试问题 解决方案1制作大小为 K 的堆并按最小距离收集点O NLogK 复杂 解决方案2 取大小为 N 的数组并按距离排序 应该使用QuickSort 霍尔修改 取前 K 点作为答案 这太复杂了 NlogN 但可以优化到近
  • 数百个空闲线程的影响

    我正在考虑使用可能数百个线程来实现通过网络管理设备的任务 这是一个在带有 Linux 内核的 powerpc 处理器上运行的 C 应用程序 在每个任务进行同步以将数据从设备复制到任务的初始阶段之后 任务变得空闲 并且仅在收到警报或需要更改一
  • 尝试使用 x86 程序集 GNU GAS 在数组索引处赋值时出现错误

    我在用x86GNU 与 GCC 的程序集 并尝试实现相当于以下内容的程序集c c int x 10 x 0 5 但是 当我尝试运行 使用命令 a out 我的汇编代码如下 第一次编译后gcc filename s 错误Segmentatio
  • 使用 NSMutableDictionary 与 NSMutableArray 造成的性能损失>

    我正在考虑使用 NSMutableDictionary 代替我当前的 NSMutableArray 这主要是出于 KVC KVO 的原因 该集合将在我的绘图方法的内循环中经历严重的变化 如果我继续进行此替换 性能是否会受到重大影响 干杯 道
  • 减法进位标志

    我正在使用 MASM32 有了这个代码 mov eax 5 sub eax 10 CF 状态标志将被设置 但使用我的铅笔和纸 我实际上看到 MSB 没有任何进位 是的 我知道从较少的数字中减去大的数字集CF 但我想知道为什么 因为使用这段代
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以
  • jQuery UI .buttonset() 太慢

    我的 HTML 页面上有几千个按钮 运行需要10多秒 buttonset buttonset 文件准备好 有没有更快的方法来做到这一点 或者是我以某种方式限制按钮数量的唯一解决方案 创建buttonset在第一次显示之前按需进行 我刚刚测试
  • 两个基本的 ANTLR 问题

    我正在尝试使用 ANTLR 来获取简单的语法并生成汇编输出 我在 ANTLR 中选择的语言是 Python 许多教程看起来非常复杂或详细阐述与我无关的事情 我真的只需要一些非常简单的功能 所以我有两个问题 将值从一个规则 返回 到另一规则
  • 为什么 GCC 不将 a*a*a*a*a*a 优化为 (a*a*a)*(a*a*a)?

    我正在对科学应用程序进行一些数值优化 我注意到的一件事是 GCC 会优化调用pow a 2 通过将其编译成a a 但是调用pow a 6 没有优化 实际会调用库函数pow 这大大降低了性能 相比之下 英特尔 C 编译器 http en wi
  • 如何有效地计算 Perl 中覆盖给定范围的范围?

    我有一个大约 30k 范围的数据库 每个范围都作为一对起点和终点给出 12 80 34 60 34 9000 76 743 我想编写一个 Perl 子例程来表示一个范围 不是来自数据库 并返回数据库中完全 包含 给定范围的范围数 例如 如果
  • 在未排序的整数列表中最优搜索 k 个最小值

    我刚刚接受采访时提出了一个问题 我很好奇答案应该是什么 问题本质上是 假设您有一个包含 n 个整数的未排序列表 您如何找到此列表中的 k 个最小值 也就是说 如果您有一个 10 11 24 12 13 列表并且正在寻找 2 个最小值 您将得
  • MSMQ 慢速队列读取

    我正在使用一个开源 Net 库 它在底层使用 MSMQ 大约一两周后 服务速度变慢 时间不准确 但一般猜测 看来发生的情况是来自 MSMQ 的消息每 10 秒才被读取一次 通常 它们会立即被读取 因此 它们将在 T 10 秒 T 20 秒
  • 为什么比较匹配的字符串比比较不匹配的字符串更快? [复制]

    这个问题在这里已经有答案了 这里有两个测量值 timeit timeit toto 1234 number 100000000 1 8320042459999968 timeit timeit toto toto number 100000
  • 什么是 __ext_vector_type__ 和 simd?

    我正在使用 Apple Metal API 以及所谓的simd图书馆 标题中有这样的代码 typedef attribute ext vector type 3 float vector float3 我很好奇它实际上做了什么以及为什么编译
  • 使用 Easy 68K (68000) 组装范围内的随机数

    我正在使用 Easy 68K 模拟器创建一个简单的黑杰克游戏 需要使用随机数来分配牌 我的牌必须在 2 到 11 的范围内 我似乎每次都得到相同的数字 但它不在我预期的范围内 我的卡值需要以 D3 结束 因此我有以下随机数代码 CLR L
  • Scipy 最小化 fmin - 语法问题

    我有一个函数 它接受多个参数 一个数组和两个浮点数 并返回一个标量 浮点数 现在我想通过改变两个参数来最小化这个函数 两个浮点数 该数组在函数内部 解包 然后使用其内容 数组和浮点数 如何使用 SciPy 的 fmin 函数来完成此操作 我
  • 通过 cmake 链接 libc++ 时 libc++abi 的链接问题

    我正在尝试构建一个简单的 hello world C 使用 LLVM Clang 3 7 0 的程序 根据工具链的源代码构建libc 使用命令行 clang std c 14 stdlib libc fno exceptions hello
  • HTML if 语句在 CDN 失败时加载本地 JS/CSS

    当从 CDN 或任何外部服务器加载 CSS JS 文件时 有可能 即使概率很低 由于外部故障而丢失该文件 在这种情况下 html 页面将因缺乏适当的 CSS 和 JS 而被损坏 有没有一种实用的方法可以在 CDN 故障时加载本地版本 IF

随机推荐

  • 限制可写入路径的记录数量(参考安全规则中的其他路径)

    假设我的 Firebase 系列如下所示 max 5 things 我将如何使用的价值max在我的安全规则中限制数量things rules things validate newData val length lt max 使用现有属性是
  • Java 中的二元运算符什么时候执行?

    我正在尝试理解java字节码 我从简单的例子开始 public class Test public static void main String args System out println 2 1 我编译了这个类 javac Test
  • Laravel 4 Auth::尝试使用电子邮件或用户名和密码

    在 laravel 中进行登录尝试时 我通常使用如下内容 if Auth attempt array email gt usernameinput password gt password true The user is being re
  • SQL Server 2005 获取任何一年中任何月份的第一个和最后一个日期

    我有一个存储过程 必须接受 int 1 12 形式的月份和 int 形式的年份 给定这两个值 我必须确定该月的日期范围 因此 我需要一个日期时间变量来表示该月的第一天 另一个日期时间变量来表示该月的最后一天 有没有一种相当简单的方法来获取这
  • 为什么Java的SimpleDateFormat解析这个

    您好 我使用自定义格式字符串设置了一个简单的日期格式 MMddyy 我给它以下值来解析 4 1 01 我认为它不应该解析这个 因为有空格 但简单日期格式正在返回日期 公元 0001 年 4 月 4 日 有什么想法为什么吗 这是预期的行为 您
  • 如何在ListView自定义适配器中使用RadioGroup?

    我想在我的列表中显示一个选择选项 我在用RadioButton in my listView排 我知道RadioGroup用于单选 但问题是我已经添加了RadioButton in my ListRowView 现在我想将所有列表项添加到一
  • 如何从模板中的指针获取类型?

    我知道如何写一些东西 但我确信有一种标准的方式来传递类似的东西func
  • 如何获取我的 Web 应用程序的基本 URL?

    是否可以通过使用获取 IIS 7 中托管的网站的基本 URLMicrosoft Web Administration ServerManager 在最简单的情况下 这将是 http localhost 但我需要以编程方式获取它 如果我不能使
  • 将 R 数据框中特定列的文本大写

    我有一个数据 看起来像这样 GO 2000974 7 8 negative regulation of pro B cell differentiation Notch1 ISS GO 2000974 7 8 negative regula
  • Android:ActivityCompat.requestPermissions 需要活动而不是上下文:/

    我调用 ActivityCompat requestPermissions 是为了获得 android M 下的权限 但是 这需要参数中的活动 这很好 只是我想从单例中调用它 并且单例可以由应用程序中的任何活动使用 ActivityComp
  • 如何确定复选框是否被选中?

    由于某种原因 我的表单不想获取复选框的值 我不确定这是否是我的编码 但是当我尝试时alert 我得到的值undefined因此 我有什么错吗
  • dropDups true 不工作 mongodb

    我在用mongoDB shell with version 3 0 2我试图确保唯一性约束username集合中的字段users 这就是我给出的 db users ensureIndex username 1 unique true 它给了
  • 从多个线程访问 SQLite DB

    考虑以下几点 我有Service 写入 DB 中AsyncTask 我的 Activity 从数据库读取数据 为简单起见 请考虑 UI 线程 我使用访问数据库SQLiteOpenHelper 我在中创建单个实例应用程序 onCreate 然
  • 无法加载库 cudnn_cnn_infer64_8.dll。错误代码 126

    Could not load library cudnn cnn infer64 8 dll Error code 126 Please make sure cudnn cnn infer64 8 dll is in your librar
  • 将 for 循环的结果保存为 r 中的向量

    我有以下 for 循环 它打印从 1 到 10 的数字 for i in 1 10 print i 如何将结果保存为向量 而不是仅仅将其打印到控制台 如果我尝试 my vector lt for i in 1 10 print i 然后打电
  • MySQL 中 ORDER BY 相等的值

    全部 我现在有以下 SQL 查询 SELECT FROM wpdb gt posts JOIN wpdb gt term relationships ON wpdb gt term relationships object id wpdb
  • 如何分析 BSOD 及其向我提供的错误信息?

    幸运的是 我没有编写过很多导致 BSOD 的应用程序 但我只是想知道这个屏幕上的信息是否有用 它是否包含任何有用的信息可以帮助我找到代码中的错误 如果是这样 我到底需要什么 然后 系统重新启动 并且可能已将一些错误日志或其他信息写入系统的某
  • UIButton 动画后没有响应

    我更愿意先从下面的链接下载项目 然后继续提问 仅 36kb 下载链接 一开始我所拥有的如下所示 当我单击 我的办公室 按钮时 我正在调用操作actionSeenButton这将打印NSLog actionSeenButton IBActio
  • 让 AVAudioEngine 重复声音

    我一直无法让下面的代码一遍又一遍地重复audioURL 处的声音 现在 它只在视图打开时播放一次 然后停止 import UIKit import AVFoundation class aboutViewController UIViewC
  • 计算两个缓冲区之间的差异似乎太慢

    我的问题 我有2个adjacent相同大小的字节缓冲区 每个大约 20 MB 我只是想数一下它们之间的差异 我的问题 该循环在具有 3600MT RAM 的 4 8GHz Intel I7 9700K 上运行需要多长时间 我们如何计算最大理