c - 如果在 C 中为 null,检查大量数据的最快方法?

标签 c performance

<分区>

我有大量数据,可能有 4MB。现在想检查其中的所有位是否都为 0。

例如: 这是数据:

void* data = malloc(4*1024*1024);
memset(data, 0, 4*1024*1024);

检查其中的所有位是否都为 0。这是我的解决方案,但速度不够快:

int dataisnull(char* data, int length)
{
    int i = 0;
    while(i<length){
        if (data[i]) return 0;
        i++;
    }
    return 1;
}

此代码可能有一些性能需要改进的地方。例如,在 32/64 位机器中,一次检查 4/8 个字节可能会更快。

所以我想知道最快的方法是什么?

最佳答案

您可以一次处理多个字节并展开循环:

int dataisnull(const void *data, size_t length) {
    /* assuming data was returned by malloc, thus is properly aligned */
    size_t i = 0, n = length / sizeof(size_t);
    const size_t *pw = data;
    const unsigned char *pb = data;
    size_t val;
#define UNROLL_FACTOR  8
#if UNROLL_FACTOR == 8
    size_t n1 = n - n % UNROLL_FACTOR;
    for (; i < n1; i += UNROLL_FACTOR) {
        val = pw[i + 0] | pw[i + 1] | pw[i + 2] | pw[i + 3] |
              pw[i + 4] | pw[i + 5] | pw[i + 6] | pw[i + 7];
        if (val)
            return 0;
    }
#endif
    val = 0;
    for (; i < n; i++) {
        val |= pw[i];
    }
    for (i = n * sizeof(size_t); i < length; i++) {
        val |= pb[i];
    }
    return val == 0;
}

根据您的具体问题,提前或延迟检测非零值可能更有效:

  • 如果全零情况最常见,您应该计算将所有位累加到 val 累加器中并仅在最后测试。
  • 如果全零的情况很少见,您应该更频繁地检查非零值。

上面的展开版本是一个折衷方案,它根据 size_t 的大小每 64 或 128 字节测试一次非零值。

根据您的编译器和处理器,您可能会通过更少或更多展开来获得更好的性能。您也可以使用适用于您的特定体系结构的内部函数来利用 vector 类型,但它的可移植性较差。

请注意,代码不会验证 data 指针是否正确对齐:

  • 它不能移植。
  • 它假定数据是通过 malloc 或类似方式分配的,因此可以正确对齐任何类型。

一如既往,对不同的解决方案进行基准测试,看看它是否会产生真正的影响。这个功能可能根本不是瓶颈,编写一个复杂的功能来优化罕见的情况会适得其反,它会降低代码的可读性,更有可能包含错误并且更难维护。例如,如果您更改内存分配方案或使用静态数组,数据对齐假设可能不成立,那么该函数可能会调用未定义的行为。

关于c - 如果在 C 中为 null,检查大量数据的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35450237/

相关文章:

R XML 计算每个节点 x 的子节点

javascript - 如何防止 JS 代码被编译器解析/评估?

asp.net - ASP.NET/数据库性能检查表

sql - 使用函数的 SQL Server 查询速度非常慢

c - 如何在运行时管理应用程序的 Debug模式?

c - 如何为多个数组动态分配内存?

c - 使用指向结构的指针在 C 中创建链表和内存分配

javascript - 为什么在 Canvas 上填充矩形会缓慢降低性能?

c - 如何求两个集合的笛卡尔积

c - fgets 不读取行的开头