Я начал изучать Go пару дней назад и пришел с его CGO и компилятором gccgo. Насколько я понимаю, это позволяет программе Go компилироваться с использованием компилятора Go и компилировать библиотеки C с помощью компилятора C и ссылаться на эти библиотеки внутри программы Go. Это действительно интересно для меня, потому что это позволяет нам использовать производительность C (при необходимости) из нашей основной программы с небольшими накладными расходами.
Однако я не уверен, насколько это мало, поэтому я спрашиваю здесь:
Были ли случаи, когда вы создавали бы библиотеку C, чтобы использовать ее изнутри вашего приложения Go? Или эта функция только для облегчения повторного использования существующего C-кода?
П.С .: Я думаю, что в настоящее время CGO не поддерживает C ++, но здесь был пост того, кто смог обернуть код C ++ с помощью функций C и успешно вызвать их.
Cgo довольно медленный, потому что Go должен возиться со временем выполнения и соглашениями о вызовах определенным образом вызывать функции C. Единственное место, где оно действительно стоит, это случаи, когда время вычислений значительно сокращается. эта стоимость. Это похоже на параллельное, распределенное, GPU и так далее программирование, хотя и с несколько более низкими затратами на запуск.
Сборка намного лучше, потому что вы можете писать ассемблер, который использует соглашение о вызовах Go, и иначе обрабатывается как собственный код Go, но сборка гораздо менее переносима, труднее для чтения и более трудоемка в обслуживании. На самом деле, стандартная библиотека Go записывает некоторые из math
а также big
пакеты в плане 9 в стиле сборки.
Gonum пример обоих из них. Он использует общую сборку для некоторых функций, которые могут быть выполнены быстрее, но также использует движки Blas и Lapack. Это обеспечивает Go-blas
реализации, но C-blas (обычно это, в конечном счете, Fortran-blas) быстрее, и для больших матричных вычислений почти всегда затрачивает меньше денег на уход из Go.
Как правило, вы хотите избежать cgo, когда это возможно. Используйте его только тогда, когда требуется значительное время вычислений, или же вам нужно взаимодействовать с вещами, с которыми нет ничего общего в чистом Go, такими как графические или звуковые драйверы, или с доступом к общим библиотекам, таким как OpenCV. Даже тогда, если вы действительно заботитесь о производительности, там, где это возможно, возможно, стоит реализовать своего рода «пул вызовов», где вы можете запланировать несколько вызовов со стороны Go и выполнять их все одновременно с одним переключением контекста на C.
Изменить: Что касается C ++, есть некоторые существенные проблемы. Может быть сложно обернуть некоторые библиотеки без нескольких уровней абстракции (поскольку cgo не может правильно обрабатывать включенные заголовки C ++). Кроме того, классы C ++ с деструкторами не могут быть возвращены по значению и должны быть размещены в куче. Так как Go не допускает детерминированного завершения ресурсов, вы должен предоставить функцию для явного освобождения памяти, и пользователь Go должен не забыть освободить ресурс. (Существует функция, о которой вы можете прочитать в документации, которая называется runtime.SetFinalizer
но я не могу сказать, что я когда-либо видел, чтобы кто-то использовал это, и сама документация идет с кучей предостережений)
Функциональность, такая как defer
делает это более управляемым, но разрушает многие вещи, такие как RAII, которые делают современные практики C ++ более безопасными.
Если бы библиотека C не выполняла большую работу за один вызов, я бы не писал код на C только для производительности. Я считаю, что cgo предназначен только для взаимодействия со старым кодом.
Причина — накладные расходы. В настоящее время вызовы функций в функции cgo в 50-100 раз медленнее, чем вызовы функций для кода Go. Затраты на вызовы функций cgo шокируют.