Compartilhar
Após escrever a entrada anterior sobre a linguagem de programação Go e ler um Comente onde é dito que ir é bastante lento, eu decidi fazer benchmarks muito simples.
A ideia é comparar a velocidade de execução do reembolso do logaritmo natural de um determinado número e a introdução dele em um mapa ou hash. Obviamente, a velocidade depende em grande medida na implementação do recipiente em cada idioma.
Quanto a ir, usei o compilador 6G com base no Inferno porque eu não quero instalar uma versão instável do Compilador GCC em Me Gentoo Linux e cagando grande, adicionando o GCGO otimiza o código mais de 6g.
Nota: Este benchmark é bastante surrado e simploso, eu apenas fiz para aliviar minha curiosidade e ver mais ou menos por onde o desempenho de Go foi. No futuro e quando tenho mais tempo, farei um sério adicionando Java, Ruby e Scala.
Implementação C
Vamos começar com o implemento em C de este benchmark simples. Eu usei as bibliotecas Uthah para criar o hash, você pode encontrá-los em sourceforge
código bechmark.c
#include <math .h>#include "uthash.h"struct map { float id; float value; UT_hash_handle hh;};struct map *dict = NULL;void add_data(float data_id, float data){ struct map *m; m = malloc(sizeof(struct map)); m->id = data_id; m->value = data; HASH_ADD_INT( dict, id, m );}int main(){ for (int i = 0; i < 5000000; i++) { add_data(i, log(i)); } return 0;}
compilação
genbeta@dev $ gcc -O3 -Wall -c -fmessage-length=0 -MMD -MP -std=c99 benchmark.cgcc -lm -o cbench benchmark.o
Implementação C ++
para C ++ Utilizamos o contêiner do mapa do código STL
benchmark.cpp
#include <iostream>#include <map>#include <cmath>using namespace std;int main(){ map <float , float> dict; for (int i = 0; i < 5000000; i++) { dict = log(i); } return 0;}
compilação
genbeta@dev $ g++ -O3 -Wall -c -fmessage-length=0 -MMD -MP benchmark.cpp -o cppbenchmark.og++ -o cppbench cppbenchmark.o
implementação em mono c #
Especialistas em .NET C # Deixe-me perdoar-me, mas não tenho idéia de c # Eu não sei se esse trecho é muito bom, mas o caso é que ele funciona muito bem, se houver algum erro que imploro para corrigir eu.
benchmark.cs
using System;using System.Collections;namespace CSBenchmark{ class MainClass { public static void Main (string args) { Hashtable dict = new Hashtable(); for (int i = 0; i < 5000000; i++) { dict.Add(i, Math.Log(i)); } } }}
compilação
genbeta@dev $ /usr/bin/gmcs /noconfig "/out:./benchmark.exe" "/r:/usr/lib/mono/2.0/System.dll" /nologo /warn:4 /debug:+ /debug:full /optimize- /codepage:utf8 /platform:x86 "/define:DEBUG" /t:exe "./benchmark.cs"
Implementação em Python
Esta é certamente mais simples de todos 🙂
código de referência
import mathd = {}for i in range(1, 5000000): d = math.log(i)
implementação em Ir
Isso também é muito simples, é mais ou menos em par com C ++
benchmark.go código
package mainimport "math"func main() { m := make(map float64) var i float64 = 1 for ; i < 5000000.; i++ { m = math.Log(i) }}
compilação
genbeta@dev $ 6g benchmark.go && 6l benchmark.6 && mv 6.out gobench
benchmarking
para a execução dos benchmarks i Use o comando de tempo do GNU no seguinte sistema:
- sistema operacional: gentoo linux
- arquitetura: x86_64
- processador: cpu Intel® Core ™ i7 @ 2.80GHz
- RAM Velocidade: 1666
Sistema de tempo | tempo | tempo real | Usando a CPU | RAM usando | alterações de contexto | |
---|---|---|---|---|---|---|
c | 1,90s | 0.27s | 2.19s | 99% | 1826704kb | 1 |
c ++ | 4.07s | 0.14s | 4.24s | 99 % | 941808kb | 1 |
c # | 1,72s | 0,29 S | 2.01s | 131% | 2032176kb | 1155 |
python CPY. Thon 2.7.2 | 3.43s | 0,37s | 3.86s | 99% | 2101312kb | 1 |
python pypy-c1.5 | 1.57s | 0,33s | 2,70 | 99% | 2442032kb | 280 |
go | 2.76S | 0.16s | 2.93s | 99% | 1044304kb | 1 |
é digno de nota como c # é o mais rápido com 2.01, eu não tenho ideia se isso é assim para A implementação do macaco, da própria língua, ou se eu não tiver feito bem o benchmark em C #, mas a verdade é que estou agradavelmente impressionado. Ainda é perto de C com 2.19s, então a implementação pypton 2.7 com 2,70, depois que ele tem uma vez para ir com 2,93, a implementação de CPYthon 2.7 continua com 3,86 e muito tristemente o último lugar C ++ está ocupado com A 4,24
Também podemos apreciar como um macaco e o pipule usar mais de um núcleo do meu processador i7, enquanto o resto só usa um núcleo em 99%.
em relação ao consumo de memória, c ++ é o mais ideal próximo por completo. C # e Python – Em ambas as implementações – faça um uso muito maior de recursos.
Go,
mas olho, esse benchmark foi executado sem usar o perfil em movimento. Em movimento, ferramentas de criação de perfil são usadas para detectar gargalos e corrigi-los melhorando consideravelmente. O papel a quem um usuário referido no post anterior é um benchmark sem perfil em ir e já teve sua resposta dos criadores da linguagem no blog oficial.Vamos usar perfil para ver o quanto podemos melhorar o desempenho de nosso snippet em vão.
primeiro, modificamos o código de nossa função para adicionar suporte para cpupproping, nosso código seria assim:
package main<br />import ( “math” “os” “flag” “log” “runtime/pprof”<br />)<br />var cpuprofile = flag.String(“cpuprofile”, “”, “write cpu profile to file”)<br />func main() { flag.Parse() if cpuprofile != “” { f, err := os.Create(cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } m := make(map float64)
var i float64 = 1 for ; i < 5000000.; i++ { m = math.Log(i) }
}
agora podemos executar o snippet com o Parâmetro CPUProfile e depuração com GOPPROF:
./gobench -cpuprofile=gobench.profgopprof gobench gobench.profWelcome to pprof! For help, type 'help'.(pprof) top10Total: 290 samples 149 51.4% 51.4% 224 77.2% hash_insert_internal 32 11.0% 62.4% 32 11.0% math.Log 17 5.9% 68.3% 17 5.9% runtime.mcpy 17 5.9% 74.1% 17 5.9% runtime.memmove 16 5.5% 79.7% 16 5.5% memhash 13 4.5% 84.1% 13 4.5% runtime.memclr 13 4.5% 88.6% 13 4.5% scanblock 8 2.8% 91.4% 250 86.2% runtime.mapassign 5 1.7% 93.1% 8 2.8% MHeap_AllocLocked 5 1.7% 94.8% 5 1.7% memwordcopy(pprof)
Podemos ver que o aplicativo ocupa a maioria dos ciclos da CPU e o tempo de execução em valores inseridos no mapa. A aplicação refinada desenvolvida em curso com Gopprof vai muito além da intenção desta entrada, mas verificando as listagens do código e as amostras usadas em cada linha que podemos saber que o gargalo está na linha que acumula 285 das 290 amostras da execução.
Está claro que o uso de um mapa para este benchmark não é ideal e poderíamos usar uma fatia para armazenar os dados. Se editarmos o arquivo e comentamos na linha /*m := make(map float64)*/
e usar uma fatia em vez de um mapa var p float64; m := make(float64, len(p))
e gerar um arquivo .prof e nós Reald:
Welcome to pprof! For help, type 'help'.(pprof) top10 -cumTotal: 25 samples 7 28.0% 28.0% 25 100.0% main.main 0 0.0% 28.0% 25 100.0% runtime.initdone 0 0.0% 28.0% 25 100.0% runtime.mainstart 18 72.0% 100.0% 18 72.0% math.Log(pprof)
Verifique que agora a prática do tempo é dedicada à função que retorna o logaritmo natural do i
e não há mais gargalo. Vamos apagar o código que introduz a funcionalidade de reforma, comentando e passamos o benchmark novamente.
tempo de usuário | tempo | tempo real | Usando a CPU | usando a RAM | alterações de contexto | ||
---|---|---|---|---|---|---|---|
ir | 0.22s | 0.01s | 0,24S | 99% | 314512kb | 1 |
Ai! Uma melhoria notável. Mas vamos ser justo, vamos mudar o hash na implementação de C por uma matriz simples e converter o benchmark para calcular o logaritmo natural do IE Inserir o valor em uma matriz.
tempo do usuário | sistema de tempo | tempo real | Uso de CPU | Uso de RAM | Alterações de contexto | |
---|---|---|---|---|---|---|
c | 0.31s | 0.00 | 0,31 S | 99% | 1824kb | 1 |
go | 0,22 s | 0.01s | 0,24S | 99% | 314512kb | 1 |
Neste caso, vá é ainda mais rápido que c devolver o logaritmo natural de i
.
conclusão
Parece que o tipo map
não é muito fino em vão, ainda assim, a velocidade . A ficção linguística é entre C e C ++. Nesse caso, não podemos fazer nada cem legítimos para eliminar o gargalo porque é uma parte específica do teste que fizemos. Eu não sei se você tem que esperar quatro anos como eu li aí que a linguagem é mais madura ou não. É claro que a maturidade ainda não tem e precisa de algumas implementações em sistemas para melhorar. E se eu souber é que eu sou pelo menos eu vou seguir a faixa, e mais agora que está disponível no Google App Engine e é mais eficiente do que Python e Java.
Mais sobre Genbeta dev | Introdução à linguagem de programação Go