这个周末,对C、Go、java、erlang做了一次无聊的性能测试。一开始只是在想了解用Go和C实现一个简单的内存数据库性能会差多少,当然不可能完整实现一个内存数据库再测试,于是我模拟了一个最简单的实验:一个内存数据库,库里面有一个表,表的每条记录固定是8个int类型的字段,不考虑动态性,不考虑查询,只做单纯的插入操作,看看执行1w次插入要多少时间。
用Go和C分别实现了代码以后,我又想到跟erlang的ets插入速度对比如何呢?用Java实现性能又如何呢?下面是测试用的代码和实验结果。
C的实现(用--std=c99参数编译):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct s_mdb_table mdb_table;
typedef struct s_mdb_row mdb_row;
struct s_mdb_table {
char* name;
mdb_row* head;
};
struct s_mdb_row {
mdb_row* prev;
mdb_row* next;
int field_1;
int field_2;
int field_3;
int field_4;
int field_5;
int field_6;
int field_7;
int field_8;
};
mdb_table* mdb_new(char* name) {
mdb_table* table = (mdb_table*)malloc(sizeof(mdb_table));
table->name = name;
table->head = NULL;
return table;
}
void mdb_insert(mdb_table* table, mdb_row* row) {
row->next = table->head;
if (table->head != NULL) {
table->head->prev = row;
}
table->head = row;
}
int main (int argc, char** argv) {
mdb_table* table = mdb_new("test_table");
clock_t t1 = clock();
for (int i = 0; i < 10000; i ++) {
mdb_row* row = (mdb_row*)malloc(sizeof(mdb_row));
mdb_insert(table, row);
}
clock_t t2 = clock();
printf("%fsn", (double)(t2 - t1) / CLOCKS_PER_SEC);
return 0;
}
Go的实现:
package main
import (
"fmt"
"time"
)
type mdb_table struct {
name string
head *mdb_row
}
type mdb_row struct {
prev *mdb_row
next *mdb_row
field_1 int
field_2 int
field_3 int
field_4 int
field_5 int
field_6 int
field_7 int
field_8 int
}
func (table *mdb_table) insert(row *mdb_row) {
row.next = table.head
if table.head != nil {
table.head.prev = row
}
table.head = row
}
func main() {
table := new(mdb_table)
table.name = "test_table";
table.head = nil;
t1 := time.Nanoseconds()
for i := 0; i < 10000; i ++ {
row := new(mdb_row)
table.insert(row)
}
t2 := time.Nanoseconds()
fmt.Printf("%fsn", float32(t2 - t1) / 1000000000)
}
Java的实现:
public class memdb
{
public static void main (String[] args)
{
DbTable table = new DbTable("test_table");
long t1 = System.nanoTime();
for (int i = 0; i < 10000; i ++)
{
DbRow row = new DbRow();
table.Insert(row);
}
long t2 = System.nanoTime();
System.out.printf("%fsn", (float)(t2 - t1) / 1000000000);
}
}
class DbTable
{
public DbTable (String name)
{
this.name = name;
this.head = null;
}
public void Insert (DbRow row)
{
row.SetNext(this.head);
if (this.head != null)
this.head.SetPrev(row);
this.head = row;
}
private String name;
private DbRow head;
}
class DbRow
{
public DbRow ()
{
}
public void SetPrev(DbRow prev)
{
this.prev = prev;
}
public void SetNext(DbRow next)
{
this.next = next;
}
private DbRow prev;
private DbRow next;
public int field_1;
public int field_2;
public int field_3;
public int field_4;
public int field_5;
public int field_6;
public int field_7;
public int field_8;
}
class DbData
{
public int field_1;
public int field_2;
public int field_3;
public int field_4;
public int field_5;
public int field_6;
public int field_7;
public int field_8;
}
erlang的实现:
-module(memdb).
-export([run/0, test/0]).
run() ->
{Time, _} = timer:tc(?MODULE, test, []),
io:format("~ps~n", [Time / 1000]).
test() ->
Table = ets:new(test_table),
insert(Table, 0).
insert(Table, 10000) ->
ok;
insert(Table, N) ->
ets:insert(Table, {N, 1, 2, 3, 4, 5, 6, 7}),
insert(Table, N + 1).
测试脚本:
#!/bin/sh
echo "C: $(./a.out)"
echo "GO: $(./6.out)"
echo "Java: $(java memdb)"
echo "Erlang: $(erl -noshell -s memdb run -s init stop)"
在我的电脑上的一次典型测试结果:
C: 0.000669s
GO: 0.003167s
Java: 0.003626s
Erlang: 0.024s
C毫无悬念的第一,Go和Java的性能相当,Go稍胜一筹,这个测试里面,其实比的是内存申请的速度,如果把内存申请的操作提前,后面1万次循环只对数据赋值,那根本没什么消耗,并且erlang用的是完整的内存数据库实现参与测试,里面包含了hash算法等耗性能的东西,这样测其实很不公平,所以我说这是一个很无聊的性能测试,呵呵。
原标签已从 2023-12-16 存档快照 恢复。本文按原站快照恢复排版,并接回已核实的本地图片。查看恢复说明