#c #golang #инспекция_кода
Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
Закрыт 2 года назад.
Решил малость побаловаться и сравнить скорость выполнения Golang и C. Просто интересно
было, насколько мой любимый Go уступает Сишке.
Первое, что пришло в голову, это функция переворачивания строки. Написал две абсолютно
одинаковые программки: на C и на Go, которые в цикле переворачивают строку 10000001
раз и подсчитывают затраченное время. Ну, и запустил, само собой.
Сказать, что счёт разгромный — это ничего не сказать, но он совершенно противоположен
ожидаемому)))
Программа на Go в среднем отрабатывает в три раза БЫСТРЕЕ аналогичной программы на
С!!! Не могу в это поверить, может, я просто не умею готовить Си и написал кривой код?
Go:
package main
import (
"fmt"
"time"
)
func main() {
var t time.Time
var s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum."
t = time.Now()
b := []byte(s)
for i := 0; i < 10000001; i++ {
reverse(b)
}
fmt.Println(time.Since(t).String())
fmt.Println(string(b))
}
func reverse(s []byte) {
var i = 0
var j = len(s) - 1
for i < j {
s[i], s[j] = s[j], s[i]
i++
j--
}
}
С:
#include
#include
#include
void reverse(char s[]);
int main()
{
time_t start, end;
char s[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.";
long i;
start = time(NULL);
for (i = 0; i < 10000001; i++) {
reverse(s);
}
end = time(NULL);
printf("%f\n", difftime(end, start));
printf("%s\n", s);
return 0;
}
void reverse(char s[])
{
int i = 0;
int j = strlen(s) - 1;
int tmp;
for (; i < j;) {
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
i++;
j--;
}
}
go version
go version go1.9 darwin/amd64
cc -v
Apple LLVM version 9.0.0 (clang-900.0.37)
Target: x86_64-apple-darwin16.7.0
Ответы
Ответ 1
GCC 4.9 (-O3) #include#include #include void reverse(char s[]); int main() { time_t start, end; char s[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; long i; start = time(NULL); for (i = 0; i < 10000001; i++) { reverse(s); } end = time(NULL); printf("%f\n", difftime(end, start)); printf("%s\n", s); return 0; } void reverse(char s[]) { int i = 0; int j = strlen(s) - 1; int tmp; for (; i < j;) { tmp = s[i]; s[i] = s[j]; s[j] = tmp; i++; j--; } } 5.000000 #include #include #include void reverse(char s[]); int len; int main() { time_t start, end; char s[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; long i; len = strlen(s); start = time(NULL); for (i = 0; i < 10000001; i++) { reverse(s); } end = time(NULL); printf("%f\n", difftime(end, start)); printf("%s\n", s); return 0; } void reverse(char s[]) { int i = 0; int j = len - 1; int tmp; for (; i < j;) { tmp = s[i]; s[i] = s[j]; s[j] = tmp; i++; j--; } } 3.000000 Golang 1.7.1 package main import ( "fmt" "time" ) var lengt int func main() { var t time.Time var s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." lengt = len(s); t = time.Now() b := []byte(s) for i := 0; i < 10000001; i++ { reverse(b) } fmt.Println(time.Since(t).String()) fmt.Println(string(b)) } func reverse(s []byte) { var i = 0 var j = lengt - 1 for i < j { s[i], s[j] = s[j], s[i] i++ j-- } } 3.573949391s Немного настораживает слишком небольшая разница и нули. -O3 непредсказуем. Добавлю вариант, предложенный в комментариях @avp и мной: #include #include #include #include void reverse(char[], int); int main() { clock_t start, end; char s[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; long i; int len = strlen(s); start = clock(); for (i = 0; i < 10000001; i++) { reverse(s, len); } end = clock(); printf("%lf\n", (double)(end-start)/CLOCKS_PER_SEC); printf("%s\n", s); return 0; } void reverse(char s[], int len) { uint64_t *i8 = (uint64_t*) s, *j8 = (uint64_t*)(s+len-8), t8; while (i8 <= j8) { t8 = __builtin_bswap64(*i8); *i8 = __builtin_bswap64(*j8); *j8 = t8; i8++; j8--; } char *i1 = (char*)i8, *j1 = ((char*)j8)+7, t1; while (i1 < j1) { t1 = *i1; *i1 = *j1; *j1 = t1; i1++; j1--; } } 1.168988 Исправлена важная ошибка в коде функции reverse() на базе __builtin_bswap64(), потому вопрос поднялся в топ. Ответ 2
Во-первых, неправильно использовать time_t и time для замера времени, поскольку оно уже в секундах. Надо использовать clock_t и clock. Во-вторых, чего никто указатели не использует? Запускаю твою программу на Go на ideone https://ideone.com/An2Ndj и получаю 1.93s. Запускаю твою же программу на Си https://ideone.com/7N8TTV - получаю 1.73s. Переделываю на указатели вместо индексов https://ideone.com/yQ2l5J - 1.50s. И вариант @Harry на плюсах с std::reverse https://ideone.com/46PqbD - 1.32s. А вообще, интересно, что варианты на Си делают ещё один проход по строке, чтобы вычислить её длину. Вариант на плюсах сразу имеет начальный и конечный указатели, а Go, вероятно, хранит длину массива где-то отдельно. Так что в варианте на си надо избавиться от strlen внутри функции и явно передавать длину. void reverse(char *str, size_t len) Код из вопроса https://ideone.com/vvwUVs - 2.04s. Код с указателями https://ideone.com/jtwTeF - 1.38s. Странно, но в этом случае кода из вопроса незначительно замедлился. Предположу, что это связано с проходом по строке в обратном направлении, при котором возникают сложности с попаданием строки в кэш процессора. Очень странно, что тот же эффект не наблюдается на коде с указателями. В любом случае интересно попробовать пройти только вторую половину строки и посмотреть, что будет. volatile int ignored = strlen(str + len / 2); Вариант из вопроса https://ideone.com/GSqG9i ускоряется до 1.68s. Вариант с указатеелями https://ideone.com/Tuluoy замедляется до 1.46s. Замечу, что 1.68 для этого кода - это быстрее обоих вариантов - и варианта с strlen, и варианта без него. А вот 1.46 - это почти 1.50 и получается, что разницы между strlen для всей строки и для её половины правктически нет. Как видно, Си всё-таки быстрее. А побеждают пока плюсы с их std::reverse, но сишный вариант с 1.38 очень близок к этим 1.32 :)
Комментариев нет:
Отправить комментарий