日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

muduo之AsyncLogging

發布時間:2025/6/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 muduo之AsyncLogging 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ??AsyncLogging是muduo的日志,程序如果直接讓文件寫日志可能會發生阻塞,所以有了異步日志這一說。muduo前端設計了2個BufferPtr,分別是currentBuffer_和nextBuffer_,還有一個存放BufferPtr的vector(buffers_)。

多個前端線程往currentBuffer_寫數據,currentBuffer_寫滿了將其放入buffers_,通知后端線程讀。前端線程將currentBuffer_和nextBuffer_替換繼續寫currentBuffer_。
后端也有2個BufferPtr,分別為newBuffer1和newBuffer2,還有一個BufferVector(buffersToWrite)。后端線程在收到前端通知之后,利用buffersToWrite和buffers_進行交換,并且用newBuffer1和newBuffer2歸還給前端的currentBuffer_和nextBuffer_,然后把日志寫入文件。

AsyncLogging.h

// Use of this source code is governed by a BSD-style license // that can be found in the License file. // // Author: Shuo Chen (chenshuo at chenshuo dot com)#include "muduo/base/AsyncLogging.h" #include "muduo/base/LogFile.h" #include "muduo/base/Timestamp.h"#include <stdio.h>using namespace muduo;//異步日志 AsyncLogging::AsyncLogging(const string& basename,off_t rollSize,int flushInterval): flushInterval_(flushInterval),running_(false),basename_(basename),rollSize_(rollSize),// 預留的日志大小thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"),// 執行該異步日志記錄器的線程latch_(1),mutex_(),cond_(mutex_),currentBuffer_(new Buffer), //當前緩沖區nextBuffer_(new Buffer),//預備緩沖區buffers_()//緩沖區隊列 {currentBuffer_->bzero(); nextBuffer_->bzero();buffers_.reserve(16);//設置緩沖區隊列大小為16 }//所有LOG_*最終都會調用append函數 void AsyncLogging::append(const char* logline, int len) {muduo::MutexLockGuard lock(mutex_);if (currentBuffer_->avail() > len) // 如果當前buffer還有空間,就添加到當前日志{currentBuffer_->append(logline, len);//調用vector的append}else{//將使用完后的buffer添加到 buffer vector后buffers_.push_back(std::move(currentBuffer_));if (nextBuffer_) // 重新設置當前buffer{currentBuffer_ = std::move(nextBuffer_);}else{currentBuffer_.reset(new Buffer); // Rarely happens//如果前端寫入速度太快了,一下子把兩塊緩沖都用完了,那么只好分配一塊新的buffer,作當前緩沖,這是極少發生的情況}currentBuffer_->append(logline, len);// 通知日志線程,有數據可寫 // 也就是說,只有當緩沖區滿了之后才會將數據寫入日志文件中cond_.notify();} }void AsyncLogging::threadFunc() // 線程調用的函數,主要用于周期性的flush數據到日志文件中 {assert(running_ == true);latch_.countDown();LogFile output(basename_, rollSize_, false);BufferPtr newBuffer1(new Buffer); //這兩個是后臺線程的buffer BufferPtr newBuffer2(new Buffer);newBuffer1->bzero();newBuffer2->bzero();BufferVector buffersToWrite; //用來和前臺線程的buffers_進行swapbuffersToWrite.reserve(16);while (running_){assert(newBuffer1 && newBuffer1->length() == 0);assert(newBuffer2 && newBuffer2->length() == 0);assert(buffersToWrite.empty());{muduo::MutexLockGuard lock(mutex_);//如果buffer為空,那么表示沒有數據需要寫入文件,那么就等待指定的時間(注意這里沒有用倒數計數器)if (buffers_.empty()) // unusual usage!{cond_.waitForSeconds(flushInterval_);}//無論cond是因何而醒來,都要將currentBuffer_放到buffers_中。 //如果是因為時間到而醒,那么currentBuffer_還沒滿,此時也要將之寫入LogFile中。 //如果已經有一個前臺buffer滿了,那么在前臺線程中就已經把一個前臺buffer放到buffers_中 //了。此時,還是需要把currentBuffer_放到buffers_中(注意,前后放置是不同的buffer, //因為在前臺線程中,currentBuffer_已經被換成nextBuffer_指向的buffer了)buffers_.push_back(std::move(currentBuffer_)); //currentBuffer_是當前緩沖區/*---歸還一個buffer---*/ // 將新的buffer轉成當前緩沖區currentBuffer_ = std::move(newBuffer1);//使用新的未使用的 buffersToWrite 交換 buffers_,將buffers_中的數據在異步線程中寫入LogFile中buffersToWrite.swap(buffers_);//內部指針交換,而非復制if (!nextBuffer_){nextBuffer_ = std::move(newBuffer2);/*-----假如需要,歸還第二個----*/}}assert(!buffersToWrite.empty());// 如果將要寫入文件的buffer列表中buffer的個數大于25,那么將多余數據刪除 // 消息堆積//前端陷入死循環,拼命發送日志消息,超過后端的處理能力//這是典型的生產速度超過消費速度,會造成數據在內存中的堆積//嚴重時引發性能問題(可用內存不足),//或程序崩潰(分配內存失敗)if (buffersToWrite.size() > 25){char buf[256];snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n",Timestamp::now().toFormattedString().c_str(),buffersToWrite.size()-2);fputs(buf, stderr);output.append(buf, static_cast<int>(strlen(buf)));// 丟掉多余日志,以騰出內存,僅保留兩塊緩沖區buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end());}// 將buffersToWrite的數據寫入到日志中for (const auto& buffer : buffersToWrite){// FIXME: use unbuffered stdio FILE ? or use ::writev ?output.append(buffer->data(), buffer->length());}// 重新調整buffersToWrite的大小 if (buffersToWrite.size() > 2){// drop non-bzero-ed buffers, avoid trashingbuffersToWrite.resize(2);}if (!newBuffer1){assert(!buffersToWrite.empty());// 從buffersToWrite中彈出一個作為newBuffer1newBuffer1 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer1->reset();// 清理newBuffer1}//前臺buffer是由newBuffer1 2 歸還的?,F在把buffersToWrite的buffer歸還給后臺bufferif (!newBuffer2){assert(!buffersToWrite.empty());newBuffer2 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer2->reset();}buffersToWrite.clear();output.flush();}output.flush(); }

AsyncLogging.cc

// Use of this source code is governed by a BSD-style license // that can be found in the License file. // // Author: Shuo Chen (chenshuo at chenshuo dot com)#include "muduo/base/AsyncLogging.h" #include "muduo/base/LogFile.h" #include "muduo/base/Timestamp.h"#include <stdio.h>using namespace muduo;//異步日志 AsyncLogging::AsyncLogging(const string& basename,off_t rollSize,int flushInterval): flushInterval_(flushInterval),running_(false),basename_(basename),rollSize_(rollSize),// 預留的日志大小thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"),// 執行該異步日志記錄器的線程latch_(1),mutex_(),cond_(mutex_),currentBuffer_(new Buffer), //當前緩沖區nextBuffer_(new Buffer),//預備緩沖區buffers_()//緩沖區隊列 {currentBuffer_->bzero(); nextBuffer_->bzero();buffers_.reserve(16);//設置緩沖區隊列大小為16 }//所有LOG_*最終都會調用append函數 void AsyncLogging::append(const char* logline, int len) {muduo::MutexLockGuard lock(mutex_);if (currentBuffer_->avail() > len) // 如果當前buffer還有空間,就添加到當前日志{currentBuffer_->append(logline, len);//調用vector的append}else{//將使用完后的buffer添加到 buffer vector后buffers_.push_back(std::move(currentBuffer_));if (nextBuffer_) // 重新設置當前buffer{currentBuffer_ = std::move(nextBuffer_);}else{currentBuffer_.reset(new Buffer); // Rarely happens//如果前端寫入速度太快了,一下子把兩塊緩沖都用完了,那么只好分配一塊新的buffer,作當前緩沖,這是極少發生的情況}currentBuffer_->append(logline, len);// 通知日志線程,有數據可寫 // 也就是說,只有當緩沖區滿了之后才會將數據寫入日志文件中cond_.notify();} }void AsyncLogging::threadFunc() // 線程調用的函數,主要用于周期性的flush數據到日志文件中 {assert(running_ == true);latch_.countDown();LogFile output(basename_, rollSize_, false);BufferPtr newBuffer1(new Buffer); //這兩個是后臺線程的buffer BufferPtr newBuffer2(new Buffer);newBuffer1->bzero();newBuffer2->bzero();BufferVector buffersToWrite; //用來和前臺線程的buffers_進行swapbuffersToWrite.reserve(16);while (running_){assert(newBuffer1 && newBuffer1->length() == 0);assert(newBuffer2 && newBuffer2->length() == 0);assert(buffersToWrite.empty());{muduo::MutexLockGuard lock(mutex_);//如果buffer為空,那么表示沒有數據需要寫入文件,那么就等待指定的時間(注意這里沒有用倒數計數器)if (buffers_.empty()) // unusual usage!{cond_.waitForSeconds(flushInterval_);}//無論cond是因何而醒來,都要將currentBuffer_放到buffers_中。 //如果是因為時間到而醒,那么currentBuffer_還沒滿,此時也要將之寫入LogFile中。 //如果已經有一個前臺buffer滿了,那么在前臺線程中就已經把一個前臺buffer放到buffers_中 //了。此時,還是需要把currentBuffer_放到buffers_中(注意,前后放置是不同的buffer, //因為在前臺線程中,currentBuffer_已經被換成nextBuffer_指向的buffer了)buffers_.push_back(std::move(currentBuffer_)); //currentBuffer_是當前緩沖區/*---歸還一個buffer---*/ // 將新的buffer轉成當前緩沖區currentBuffer_ = std::move(newBuffer1);//使用新的未使用的 buffersToWrite 交換 buffers_,將buffers_中的數據在異步線程中寫入LogFile中buffersToWrite.swap(buffers_);//內部指針交換,而非復制if (!nextBuffer_){nextBuffer_ = std::move(newBuffer2);/*-----假如需要,歸還第二個----*/}}assert(!buffersToWrite.empty());// 如果將要寫入文件的buffer列表中buffer的個數大于25,那么將多余數據刪除 // 消息堆積//前端陷入死循環,拼命發送日志消息,超過后端的處理能力//這是典型的生產速度超過消費速度,會造成數據在內存中的堆積//嚴重時引發性能問題(可用內存不足),//或程序崩潰(分配內存失敗)if (buffersToWrite.size() > 25){char buf[256];snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n",Timestamp::now().toFormattedString().c_str(),buffersToWrite.size()-2);fputs(buf, stderr);output.append(buf, static_cast<int>(strlen(buf)));// 丟掉多余日志,以騰出內存,僅保留兩塊緩沖區buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end());}// 將buffersToWrite的數據寫入到日志中for (const auto& buffer : buffersToWrite){// FIXME: use unbuffered stdio FILE ? or use ::writev ?output.append(buffer->data(), buffer->length());}// 重新調整buffersToWrite的大小 if (buffersToWrite.size() > 2){// drop non-bzero-ed buffers, avoid trashingbuffersToWrite.resize(2);}if (!newBuffer1){assert(!buffersToWrite.empty());// 從buffersToWrite中彈出一個作為newBuffer1newBuffer1 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer1->reset();// 清理newBuffer1}//前臺buffer是由newBuffer1 2 歸還的。現在把buffersToWrite的buffer歸還給后臺bufferif (!newBuffer2){assert(!buffersToWrite.empty());newBuffer2 = std::move(buffersToWrite.back());buffersToWrite.pop_back();newBuffer2->reset();}buffersToWrite.clear();output.flush();}output.flush(); }

?

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的muduo之AsyncLogging的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。