日志系统项目已经编写完成,在本节完成性能测试之后就正式结束了
测试代码如下
#include "../logs/mjwlog.h"
#include <vector>
#include <thread>
//参数:日志器名称,线程数量,输出日志条数,单条日志大小
void perform(const std::string& loggername,const size_t thread_count,const size_t msg_count,const size_t msg_size)
{
//1. 获取日志器
mjwlog::Logger::ptr logger = mjwlog::LoggerManage::GetInstance().GetLogger(loggername);
if(logger.get()==nullptr) return;
//2. 创建日志信息
std::string msg(msg_size,'#');
//3. 创建多线程
std::vector<double> cost_time;
std::vector<std::thread> threads;
size_t singal_thread_ologs=msg_count/thread_count;//单个线程需要输出的日志条数
std::cout<<"总输出日志条数:"<<msg_count<<"条"<<" 输出日志总大小:"<<(msg_count*msg_size)/(1024*1024)<<" MB"<<std::endl;
for(int i=0;i<thread_count;i++)
{
threads.emplace_back([&,i,singal_thread_ologs](){
//4. 开始时间
auto start=std::chrono::high_resolution_clock::now();
//5. 开始输出
for(int j=0;j<singal_thread_ologs;j++)
{
logger->fatal("%s",msg.c_str());
//std::cout<<"输出"<<std::endl;
}
//6. 结束时间
auto end=std::chrono::high_resolution_clock::now();
//记录结果
std::chrono::duration<double> result=end-start;
cost_time.push_back(result.count());
//输出该线程测试信息
std::cout<<"线程"<<i<<" 输出日志数量:"<<singal_thread_ologs<<" 耗时: " << result.count() << "s\n";
});
}
//回收线程
for(int i=0;i<thread_count;i++)
{
threads[i].join();
}
//7.计算总耗时
//多线程输出时,由于多个线程并非执行,因此计算总耗时并不是所有线程所消耗时间相加
//而是取最大耗时
double max_cost_time=cost_time[0];
for(int i=0;i<thread_count;i++)
{
max_cost_time=max_cost_time<cost_time[i]?cost_time[i]:max_cost_time;
}
std::cout<<max_cost_time<<std::endl;
size_t msg_pre_sec=msg_count/max_cost_time;//每秒打印日志条数
size_t size_pre_sec=(msg_count*msg_size)/(max_cost_time*1024*1024);//每秒输出大小,单位MB
//8. 输出结果
std::cout<<"总耗时:"<<max_cost_time<<"s"<<std::endl;
std::cout<<"每秒输出日志条数:"<<msg_pre_sec<<std::endl;
std::cout<<"每秒输出大小:"<<size_pre_sec<<" MB"<<std::endl;
}
//同步日志器性能测试
void sync_perform()
{
std::unique_ptr<mjwlog::LoggerBuild> lb(new mjwlog::GlobalLoggerBuild());
lb->BuildDefaultLevel(mjwlog::LogLevel::level::WARN);
lb->BuildFormat("%m%n");
lb->BuildLoggerName("sync_logger");
lb->BuildSink<mjwlog::FileSink>("./logfile/sync_logger.log");
lb->BuildLoggerType(mjwlog::type::SyncLogger);
lb->build();
//单线程
//perform("sync_logger",1,1000000,100);
//多线程
perform("sync_logger",5,1000000,100);
}
//异步日志器性能测试
void async_perform()
{
std::unique_ptr<mjwlog::LoggerBuild> lb(new mjwlog::GlobalLoggerBuild());
lb->BuildDefaultLevel(mjwlog::LogLevel::level::WARN);
lb->BuildFormat("%m%n");
lb->BuildLoggerName("async_logger");
lb->BuildSink<mjwlog::FileSink>("./logfile/async_logger.log");
lb->BuildLoggerType(mjwlog::type::AsyncLogger);
lb->BuileUnsafeBuffer();//开启不安全测试模式
lb->build();
//单线程
//perform("async_logger",1,1000000,100);
//多线程
perform("async_logger",5,1000000,100);
}
int main()
{
async_perform();
return 0;
}
主要测试要素:同步/异步 & 单线程/多线程
1. 输出100w+条指定长度日志所需时间
2. 每秒可以输出多少条日志
3. 每秒可以输出多少大小的日志(MB)
测试环境
腾讯云服务器
CPU:2核
内存:2G
硬盘:SSD运营盘 40G
系统:CentOS 7.6 64bit
同步日志下单线程
同步日志下多线程
异步日志下单线程
异步日志下多线程
从上面的实验数据我们发现,在单线程的情况下异步日志器还没有同步日志器效率高,这是因为现在的I/O操作在用户态都会有缓冲区进行缓冲,因此我们当前测试用例看起来的同步实际上也是在操作内存,只有在缓冲区满了才会涉及到阻塞磁盘写入,而我们异步日志器效率比较低是因为单线程异步日志器中也存在大量的锁冲突,而同步日志器则没有,因此性能异步日志器性能有一定程度上的降低
当我们切入到多线程后,发现同步日志器性能不但没有提升而且还下降了,而异步日志器性能则有有效的提升,这是因为同步日志器要将日志亲自写入到磁盘中,因此其性能上限收到磁盘读写速度的限制,即使多线程也难以提升,反而因为锁冲突导致性能下降;而异步日志器上限则是CPU的处理性能,日志输出时不会因为落地而阻塞,因此多线程下有了显著提升。
当然这是在云服务器的渣机下的实验数据,如果在各位自己的电脑上实验相信能够更上一层楼。