我的代码中有一个标准的DFS实现,它在每次调用时使用动态分配的堆栈。
我称这个功能很多。通常仅在小规模(200-1000)个节点上运行,但有时会有一个大型连接组件,其节点数量超过一百万个。
分析器显示在分配堆栈时浪费了大量的计算时间。我想尝试重用现有的内存(例如调用堆栈)。但是,该功能必须保持线程安全。
是否有一种有效的方法可以动态使用调用堆栈而不会使函数递归?
到目前为止,我最好的想法是使用额外的参数使函数递归,该参数在每次后续调用时使自动堆栈大小加倍。
伪C:
void dfs(size_t stack_length, void * graph, graphnode_t start_node) {
graphnode_t stack[stack_length];
size_t stack_size = 0;
for (all nodes) {
// do something useful
if (stack_size < stack_length) {
stack[stack_size++] = new_node;
} else {
dfs(stack_length * 2, graph, new_node);
}
}
}
答案 0 :(得分:0)
听起来你正在描述你的算法只用一个graphnode_t
数组就可以正常运行(尽管你称之为堆栈,我认为这不适用于此),唯一真正的问题是你不确定开始时应该有多大。
如果是这种情况,我建议首先不要让这个(可能很大的)数组成为局部变量,因为这会导致实际程序堆栈出现问题。而是让它成为一个静态指针,指向动态大小的内存,如果需要,你可以定期扩展。
ensure_size(graphnode_t **not_a_stack_ptr, unsigned long *length_ptr)
{
if (!*not_a_stack_ptr)
{
*not_a_stack_ptr = malloc(sizeof(graphnode_t) * MINIMUM_ENTRY_COUNT);
*length_ptr = MINIMUM_ENTRY_COUNT;
}
else if (size needs to double)
{
*length_ptr *= 2;
*not_a_stack_ptr = realloc(*not_a_stack_ptr, sizeof(graphnode_t) * (*length_ptr));
}
}
struct thread_arguments {
void * graph;
graphnode_t start_node;
}
dfs_thread(void *void_thread_args)
{
struct thread_arguments *thread_args = void_thread_args;
graphnode_t *not_a_stack = NULL;
unsigned long not_a_stack_length = 0;
for (all nodes)
{
ensure_size(¬_a_stack, ¬_a_stack_length);
stack[stack_size++] = new_node;
}
if (not_a_stack) free(not_a_stack);
}
注意:您的伪代码表明可以根据您拥有的节点数确定最大大小。通过使用它来预先执行一个完整大小的malloc,您将获得最大的性能提升。