C 哪个更快:适当的数据输入还是适当的数据结构?
我有一个数据集,其列如下所示:C 哪个更快:适当的数据输入还是适当的数据结构?,c,performance,C,Performance,我有一个数据集,其列如下所示: Consumer ID | Product ID | Time Period | Product Score 1 | 1 | 1 | 2 2 | 1 | 2 | 3 等等 作为程序(用C编写)的一部分,我需要处理所有消费者给出的特定产品的产品分数以及所有可能组合的时段组合。假设有3个产品和2个时间段。然后我需要处理所有可能组合的产品分数,如下所示:
Consumer ID | Product ID | Time Period | Product Score
1 | 1 | 1 | 2
2 | 1 | 2 | 3
等等
作为程序(用C编写)的一部分,我需要处理所有消费者给出的特定产品的产品分数以及所有可能组合的时段组合。假设有3个产品和2个时间段。然后我需要处理所有可能组合的产品分数,如下所示:
Product ID | Time Period
1 | 1
1 | 2
2 | 1
2 | 2
3 | 1
3 | 2
我需要按照上述路线多次处理数据(>10k),并且数据集相当大(例如,48k消费者、100种产品、24个时段等)。所以速度是个问题
我想出了两种处理数据的方法,我想知道哪种方法更快,或者说这没什么大不了的?(速度问题,但不以过度维护/可读性为代价):
有什么想法吗?有没有其他加快处理速度的方法?谢谢与许多与性能相关的问题一样,唯一真实、明确的答案是编写基准测试。速度将取决于许多事情,而且听起来你不是在谈论线性算法与二次算法的简单对比(即使这样也会对输入大小产生额外的依赖)
因此,实现这两种方法,在样本数据上运行它们,并对结果计时。这将比我们试图在有限的信息下在头脑中解决问题更快、更具决定性。我建议过滤数据,如第二步,然后按照第一步进行处理。如果您的性能不可接受,请调整性能。为基线设置一些基准,然后尝试一些不同的方法
在大多数实际情况下,我建议不要仅仅为了基准测试而实现多种方法。性能可能类似。如果它不相似,那么它的性能可能很差,显然需要调整。您最好将时间花在实现其他功能上。这将使数据库表变得很小。如果存在完整的消费者/产品/时间矩阵,则数据量约为0.4GB。您是否考虑过用SQL运行整个过程?即使你不给我们一个完整的数据库;对于这种大小的数据,为每个可能的排序顺序生成一个完整的表并将每个表转储到一个文件中是可行的。然后,您可以加载您需要的任何文件,以便按照您选择的顺序遍历它
此外,如果您可以并行运行整个10K过程,或者每次至少运行几十个过程,那么您可能会提前这样做,因为这可能会大大减少IO等待和/或缓存未命中 实际上这两种方法看起来非常相似。为了存储为特定组合提供分数的所有客户的客户id,您需要对数据进行排序或执行更昂贵的操作
你能用空间换时间吗?如果是,则不进行任何预处理,而是创建一个包含所有组合(10x24)的数组来存储分数。在数据出现时对其进行处理,并更新特定组合的分数。如果您需要平均分数,请存储提供分数的客户总数和数量。您影响最慢的部分可能是复制内存块。因此,应用的第一种技术是将每一行的值放在一个结构中,并仅通过指针引用它,直到所有处理完成为止。结构类似于:
typedef struct {
int consumer;
int product;
int time;
int score;
} rowData;
在此基础上,我认为您最好遍历输入行,建立由消费者和产品标识的结构的二叉树(或其他排序结构),并包含指向所有匹配行数据的指针的查找表:
typedef struct {
int consumer;
int product;
rowData * matches;
} matchLut;
一旦所有行都放在树上的查找表中,就可以处理每个包。如果内存允许,可以将数据存储在2d数组中(实际上是3d数组,但我稍后会讨论)。此数组将按(产品id、时间段)索引 若您对数据的处理允许,那个么2D数组的每个元素都可以是新数据的累加器,所以您可以读入一个数据元素,然后调整2D数组的相应元素以反映它。如果此方法有效,则在中完成数据读取后,将对其进行处理 如果处理过程要求每个数据元素的数据同时存在,则可以将2D数组的每个元素制作为列表(这是第三个D)。如果您不知道每个(产品id、时间段)会有多少客户条目,那么它可能是一个可变长度的列表。读入数据后,需要重新访问二维数组的每个元素以处理每个列表。如何安排阵列以及如何访问元素将影响性能。 您可能希望动态地声明它,但对于本例
struct element_t element[NUMBER_OF_PRODUCTS][NUMBER_OF_TIME_PERIODS];
// don't forget to initialize these elements to empty
...
for (p = max_product_id; p >= 0; p--) {
for (t = max_time_period; t >= 0; t--) {
process(element[p][t]);
}
}
如果您想在转移到下一个产品之前处理每种产品,则效果会更好。如果要在移动到下一个时间段之前处理每个时间段(对于所有产品),可以交换声明的行、列和循环,以获得更好的缓存命中率
您应该注意,这会为您进行排序,而不会说“排序此数据”
如果内存不允许,那么您可能希望在读取数据时将部分数据存储到文件中。这与上面提到的阵列/循环组织/缓存命中优化问题相同,但会被放大很多倍。在读取主数据结束时,您希望能够处理特定临时文件中的所有数据(可能包含给定产品的所有数据)