小编P..*_*...的帖子

我对AoS vs SoA的理解是对吗?

我最近一直在阅读AoS vs SoA结构设计和面向数据的设计.很难找到关于这两者的信息,而且我发现的东西似乎比我拥有更多的处理器功能.也就是说,我对前一个主题的理解特别导致了一些我认为应该能够理解答案的问题.

首先,为了确保我的理解不是基于错误的前提,我对AoS vs SoA的功能和利弊的理解,应用于具有'Name'和'Age'字段的'Person'记录的集合与他们相关:

阵列的结构

  • 将数据存储为由多个数组组成的单个结构,例如,将People字段Names作为字符串Ages数组和整数数组作为对象.
  • 信息,说,第三人的名单将通过类似给予People.Names[2]People.Ages[2]
  • 优点:
    • 当仅处理来自许多"人"记录的一些数据时,只需要从内存加载该数据.
    • 所述数据以同类方式存储,允许在大多数此类情况下通过SIMD指令更好地使用高速缓存.
  • 缺点: - 当需要一次访问多个字段时,上述优点就会消失. - 访问一个或几个对象的所有数据变得效率较低. - 大多数编程语言需要更冗长,更难以读/写的代码,因为没有明确的"Person"结构.

结构数组

  • 将数据存储为多个结构,每个结构都有一整套字段,它们本身存储在所有这些结构的数组中,例如对象People数组Person,它们具有Name字符串字段和Age整数字段.
  • 对于第三人的信息会被像被赋予People[2].NamePeople[2].Age
  • 优点:
    • 代码围绕一个更简单的心理模型构建,间接被抽象掉.
    • 单个记录易于访问和使用.
    • Person结构的存在使得在大多数编程语言中编写代码变得更加简单.
  • 缺点:
    • 当处理来自大量记录的一些数据时,需要将整组结构加载到包括不相关数据的存储器中.
    • 结构阵列不是均匀的,在这种情况下限制了SIMD指令可以提供的优点.

它的长短似乎是,假设为了论证,你的性能瓶颈是数据访问和编码的简易性是无关紧要的,如果你几乎完全需要一次访问大量的单个字段数据SoA可能更具性能,而如果您经常需要从同一个对象访问多个字段或处理单个对象而不是一次处理多个字段,AoS将更具性能.

也就是说,我一直在阅读的一些内容似乎让图片变得混乱.首先,多个消息来源已经声明SoA需要索引寻址,据称这是低效的.我无法理解这一点,也无法找到任何解释.在我看来,AoS和SoA需要完全相同的操作来访问任何特定的数据,尽管顺序不同,除了SoA需要一个额外的指针(可能多于一个,取决于所使用的结构类型).稍微简化一下,为了在AoS下面的上面例子中得到第五个人的年龄,你首先得到指向数组的指针,向它添加4,在数组的那个元素处获取结构指针,添加一个大小字符串指向它,因为age是第二个字段,然后访问该指针处的整数.在SoA下,您将获得指向结构的指针并向其添加字符串数组指针的大小以获取年龄列表,然后获取指向存储在那里的整数列表的指针并向其添加4,然后获取整数存储在那里.

其次,我不清楚SoA的好处在多大程度上取决于特定的CPU架构.一方面,我对上述优点的理解并不依赖于任何特定的体系结构,除了SIMD指令在某些情况下可以提供AoS下无法提供的额外好处.另一方面,我看到声称可以限制SoA的优势,具体取决于特定SIMD架构中可用的通道数量.同样,这似乎只会影响SIMD指令可以提供的更多通用缓存优势的额外好处.

最后,我已经看到SoA在遍历数据时需要更多缓存方式的说法.我不完全确定缓存方式是什么或者什么,如果有的话,特别是'遍历'数据.我最好的猜测是"缓存方式"指的是关联缓存中潜在冲突的数量或与之相关,并且它与上面提到的第二个Con相关.

memory caching sse simd data-oriented-design

15
推荐指数
1
解决办法
3104
查看次数

测量速度时List.Contains和List.IndexOf的行为不一致

我需要使用C#快速处理大量字符串.为了找到最快的方法,我一直在使用以下基准测试功能:

delegate void Test();
static void time(Test test, int iter, string label)
    {
        Stopwatch timer = new Stopwatch();
        timer.Reset();
        timer.Start();

        int i = 0;
        while (i < iter)
        {
            test();
            i++;
        }

        Console.WriteLine(label + ": " + timer.ElapsedMilliseconds.ToString());
        timer.Reset();
    }
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时:

int iter = 10000000;
string[] array = new string[] { "cat", "dog", "horse", "cow", "dimorphodon", "a", "a", "dog", "horse", "cow", "dimorphodon", "a", "a", "pig" };
List<string> list = new List<string>(array);

time(() => { int i = 0; while (i …
Run Code Online (Sandbox Code Playgroud)

c# performance benchmarking list

4
推荐指数
1
解决办法
168
查看次数

以 Null 终止 C 可变参数函数的参数列表

我正在摆弄 C 中的可变参数函数来了解它们是如何工作的,并且正在尝试构建一个简单的“打印行”函数,而不需要手动计算行数。我通过将函数包装在一个宏中来实现此目的,该宏将空指针添加到char *参数列表的末尾,以便该函数可以逐行打印,直到找到空参数。

我知道我已经避免了一些常见的陷阱,例如忘记在参数列表中强制转换空指针,但无论出于何种原因,该代码仍然无法正常工作。使用任意数量的参数调用该函数都会正确打印它们,然后无法检测空值,打印一堆垃圾数据,然后崩溃。

int printline(const char *str) {
    printf("%s\n", str);
}

#define printlines(...) _comments(__VA_ARGS__, (char*)0)
int _printlines(char* first, ...) {
    if (first) {
        printline(first);

        va_list ptr;
        va_start(ptr, first);

        char *next;

        do {
            char *next = va_arg(ptr, char *);
            if (next) {
                printline(next);
            }
        } while(next);

        va_end(ptr);
    }
}

int main() {
    printlines("hi");
    //prints 'hi', then prints garbage data and crashes

    printlines("how", "are", "you");
    //prints 'how', 'are', and 'you', then prints garbage data and crashes
    
    _printlines("help", (char …
Run Code Online (Sandbox Code Playgroud)

c variadic

0
推荐指数
1
解决办法
243
查看次数