• LevelDB和ForestDB简单性能测试(含代码)


    测试环境简单说明

    Windows下测试

    硬件环境如下:
    处理器:Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz
    内 存:8GB
    硬 盘:希捷 ST1000DM003
    操作系统:Windows 10 企业版
    编译说明:
    两个都是使用VS2015编译的64位Release版本。运行时库采用动态多线程版本(MD)

    Linux下测试

    硬件环境如下:
    处理器:Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
    内 存:8GB
    硬 盘:金士顿64G SSD
    操作系统:ArchLinux (Linux version 4.8.13-1-ARCH)
    编译说明:
    两个都是使用Gcc 6.2.1编译的x64版本,使用-O2参数优化。

    测试结果

    LevelDBForestDB进行简单的性能测试。
    两个都在单线程下进行10000次的增删查改测试,共测试5次。(这里测试的次数有点少,应该测试十万次以上的)
    测试的时候可以发现(设置断点),Forest每次操作都将数据缓存在内存了,内存占用比较大。而LevelDB在添加的时候并没有缓存,但是在数据获取和修改的时候内存会变大。
    总体上LevelDB占用内存小一点,但是linux下速度不及ForestDB(非常接近)。易用程度上,LevelB简单得多。磁盘占用的情况的话,Forest对磁盘使用比较少,这10000条数据占了13MB左右,而LevelDB则占了120MB左右。

    Windows下测试结果

    测试结果平均值对比直方图:
    测试结果对比直方图

    LevelDB 测试结果截图
    LevelDB 测试结果截图

    ForestDB 测试结果截图
    ForestDB 测试结果截图

    Linux下测试结果

    测试结果平均值对比直方图:
    测试结果对比直方图

    LevelDB 测试结果截图
    LevelDB 测试结果截图

    ForestDB 测试结果截图
    ForestDB 测试结果截图

    测试代码

    LevelDB测试代码

    #include <cassert>  
    #include <string>  
    #include <iostream>
    #include <chrono>
    
    #include "leveldb/db.h"  
    
    #define TEST_FREQUENCY	(10000)
    
    char* randomstr()
    {
    	static char buf[1024];
    	int len = rand() % 768 + 255;
    	for (int i = 0; i < len; ++i) {
    		buf[i] = 'A' + rand() % 26;
    	}
    	buf[len] = '';
    	return buf;
    }
    
    int main() 
    {
    	leveldb::DB* db;
    	leveldb::Options options;
    	options.create_if_missing = true;
    
    	// 打开数据库
    	leveldb::Status status = leveldb::DB::Open(options, "./testdb", &db);
    	assert(status.ok());
    
    	srand(2017);
    	std::string k[TEST_FREQUENCY];
    	for (int i = 0; i < TEST_FREQUENCY; ++i) {
    		k[i] = (randomstr());
    	}
    	std::string v("壹贰叁肆伍陆柒捌玖拾");
    	v.append(v).append(v).append(v).append(v).append(v);
    
    	// 测试添加
    	{
    		auto start = std::chrono::system_clock::now();
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = db->Put(leveldb::WriteOptions(), k[i], v);
    			assert(status.ok());
    		}
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次添加耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    	// 测试获取
    	{
    		auto start = std::chrono::system_clock::now();
    		std::string v2[TEST_FREQUENCY];
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = db->Get(leveldb::ReadOptions(), k[i], &v2[i]);
    			assert(status.ok());
    		}
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次获取耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    		// 验证获取结果是否正确
    		std::string ss;
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			if (v2[i] != v) {
    				std::cout << "第 " << i << " 个结果不正确" << std::endl;
    				std::cout << v2[i] << std::endl;
    			}
    		}
    	}
    	// 测试修改
    	{
    		auto start = std::chrono::system_clock::now();
    		v.append(v);
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = db->Put(leveldb::WriteOptions(), k[i], v);
    			assert(status.ok());
    		}
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次修改耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    
    	// 测试删除
    	{
    		auto start = std::chrono::system_clock::now();
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = db->Delete(leveldb::WriteOptions(), k[i]);
    			assert(status.ok());
    		}
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次删除耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    	delete db;
    	return 0;
    }
    

    Forest 测试代码

    #include <cassert>  
    #include <string>  
    #include <iostream>
    #include <chrono>
    
    #include "libforestdb/forestdb.h"
    
    #define TEST_FREQUENCY	(10000)
    
    char* randomstr()
    {
    	static char buf[1024];
    	int len = rand() % 768 + 255;
    	for (int i = 0; i < len; ++i) {
    		buf[i] = 'A' + rand() % 26;
    	}
    	buf[len] = '';
    	return buf;
    }
    
    int main()
    {
    	fdb_file_handle* fdbFileHandle = nullptr;
    	fdb_kvs_handle* fdbKvsHandle = nullptr;
    	fdb_status status;
    
    	// 初始化ForestDB
    	// 1、文件配置设置配置
    	fdb_config fileConfig = fdb_get_default_config();
    	{// WAL阈值4K
    		fileConfig.wal_threshold = 4096;
    		// 缓存大小64MB
    		fileConfig.buffercache_size = 64 * 1024 * 1024;
    		// 设置使用默认的kvs
    		fileConfig.multi_kv_instances = false;
    		// 关闭循环块复用
    		fileConfig.block_reusing_threshold = 100;
    		// 使用序列树
    		fileConfig.seqtree_opt = FDB_SEQTREE_USE;
    	}
    	// 2、使用设置的配置进行初始化
    	status = fdb_init(&fileConfig);
    	assert(status == FDB_RESULT_SUCCESS);
    
    	// 打开数据库
    	status = fdb_open(&fdbFileHandle, "./testdb", &fileConfig);
    	assert(status == FDB_RESULT_SUCCESS);
    	// 打开kvs
    	fdb_kvs_config kvsConfig = fdb_get_default_kvs_config();
    	status = fdb_kvs_open_default(fdbFileHandle, &fdbKvsHandle, &kvsConfig);
    	assert(status == FDB_RESULT_SUCCESS);
    
    
    	srand(2017);
    	std::string k[TEST_FREQUENCY];
    	for (int i = 0; i < TEST_FREQUENCY; ++i) {
    		k[i] = (randomstr());
    	}
    	std::string v("壹贰叁肆伍陆柒捌玖拾");
    	v.append(v).append(v).append(v).append(v).append(v);
    
    	// 测试添加
    	{
    		auto start = std::chrono::system_clock::now();
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
    			assert(status == FDB_RESULT_SUCCESS);
    		}
    		// 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
    		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
    
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    	
    		std::cout << TEST_FREQUENCY <<"次添加耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    	// 测试获取
    	{
    		auto start = std::chrono::system_clock::now();
    		void* v2[TEST_FREQUENCY]; size_t v2len[TEST_FREQUENCY];
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = fdb_get_kv(fdbKvsHandle, k[i].data(), k[i].size(), &v2[i], &v2len[i]);
    			assert(status == FDB_RESULT_SUCCESS);
    		}
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次获取耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    		// 验证获取结果是否正确
    		std::string ss;
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			ss.assign((const char*)v2[i], v2len[i]);
    			if (ss != v) {
    				std::cout << "第 " << i << " 个结果不正确" << std::endl;
    				std::cout << ss << std::endl;
    			}
    			free(v2[i]);
    		}
    	}
    	// 测试修改
    	{
    		auto start = std::chrono::system_clock::now();
    		v.append(v);
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
    			assert(status == FDB_RESULT_SUCCESS);
    		}
    		// 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
    		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
    
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次修改耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    
    	// 测试删除
    	{
    		auto start = std::chrono::system_clock::now();
    		for (int i = 0; i < TEST_FREQUENCY; ++i) {
    			status = fdb_del_kv(fdbKvsHandle, k[i].data(), k[i].size());
    			assert(status == FDB_RESULT_SUCCESS);
    		}
    		// 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
    		fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
    
    		auto end = std::chrono::system_clock::now();
    		auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    		std::cout << TEST_FREQUENCY <<"次删除耗时: "
    			<< double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
    			<< "秒" << std::endl;
    	}
    	
    	// 关闭数据库
    	status = fdb_kvs_close(fdbKvsHandle);
    	assert(status == FDB_RESULT_SUCCESS);
    	status = fdb_close(fdbFileHandle);
    	assert(status == FDB_RESULT_SUCCESS);
    	status = fdb_shutdown();
    	assert(status == FDB_RESULT_SUCCESS);
    	return 0;
    }
    
  • 相关阅读:
    基于Java的Socket类Tcp网络编程实现实时聊天互动程序(一):QQ聊天界面的搭建
    前端开发者的福音!通过拖拽就可生成Vue代码的平台来了!
    爬虫实战 如何爬取B站视频评论?
    年轻就该多尝试,教你20小时Get一项新技能
    利用Python将多张图片合成视频
    利用myqr库创建自己的二维码
    用Python爬取日向、樱坂成员blog中的JPG文件的url并将其下载到本地
    【MemSQL Start[c]UP 3.0 Round 1 A】 Declined Finalists
    【MemSQL Start[c]UP 3.0 Round 1 E】Desk Disorder
    【MemSQL Start[c]UP 3.0 Round 1 C】 Pie Rules
  • 原文地址:https://www.cnblogs.com/oloroso/p/6306352.html
Copyright © 2020-2023  润新知