如何在golang中正确使用judy数组库?

时间:2013-12-27 03:49:10

标签: go

在golang中,调用C库的方式与其他大型机动态语言(如PHP / Python / Java)中使用的方式不同,因为Golang具有不同的基于OS线程的多任务机制,因此调用c函数可能会导致上下文我理解切换或线程切换。在我的项目中,我试图在Golang中使用Judy Array(作为队列工作者)来做一些简单但大量的与dict相关的计算,比如“select distinct”,所以

  

最佳实践涉及这样的c lib(用于相对高密度的计算),并尽可能地降低引入的性能开销?

2 个答案:

答案 0 :(得分:1)

尽管有标题,但这里的问题实际上有两个部分:一个关于golang的通用关于效率的C接口,另一个是关于judy数组的高效使用的特定问题。

这个主题似乎总结了成本:https://groups.google.com/forum/#!topic/golang-nuts/RTtMsgZi88Q,所以是因为它比直接C更昂贵,你应该尽量减少从Go到C的交叉点。

这里有额外的,judy数组特定的建议:我之前在C / C ++代码中使用过judy数组。图书馆的界面在某些地方并不直观。默认情况下,它使用基于C-macro的API,这使得接口使用正确变得棘手,因为编译器无法像往常一样提供足够的帮助。

因此,我建议您首先在C中编写测试和基准测试,以便了解API及其奇怪的情况。 Judy数组在为我的应用程序进行基准测试时(对比字符串的C ++向量)快了3倍,所以它值得。但将任务分为三个阶段。首先在C中执行您想要执行的操作,并确保它在您自己的C代码中按预期工作。然后展开基本的C接口来处理您需要完成的批量处理,以便最大限度地减少Go-> C交换机的数量。然后从Go绑定新的C接口。

答案 1 :(得分:0)

如果您从头开始对库进行绑定,我首先要以最直接的方式使用cgo,然后查看性能是否符合您的要求。

如果没有,请尝试最小化您在通常称为的点中进行的C调用次数。正如您在问题中已经提到的那样,当进行C调用时,Go会切换到不同的堆栈,如果您对简单函数进行大量cgo调用,这将影响性能。因此,提高性能的一种方法是减少C调用的总数。

例如,如果您需要调用多个C函数来在Go API中实现一个操作,请考虑是否可以编写一个可以组合这些调用的小型Shim C函数。

如果您正在包装的API处理大量字符串,如果您有许多调用,这可能会显示:

func foo(bar string) {
    cBar := C.CString(bar)
    defer C.free(unsafe.Pointer(cBar)
    C.foo(cBar)
}

这是三个C电话。如果您要包装的API可以处理未终止的字符串,则此处的一个选项是将指向字符串的指针传递给包装器,并使用生成的GoString中定义的_cgo_export.h类型。例如,在Go方面:

func foo(bar string) {
    C.foo_wrapper(unsafe.Pointer(&bar))
}

在C方面:

#include "_cgo_export.h"
void foo_wrapper(void *ptr_to_string) {
    GoString *bar = ptr_to_string;
    foo_with_length(bar->p, bar->n);
}

只要库在foo_wrapper返回时没有保留过去的字符串数据,这应该是安全的。

可能还有一些其他优化可能有所帮助,但我强烈建议您最初保持简单,并努力优化重要的领域。