c/c++日志庫初識

C/C++日志庫:從入門到實踐的深度指南

在軟件開發的世界里,日志(Logging)扮演著一個沉默卻至關重要的角色。它像是飛行記錄儀的“黑匣子”,記錄著應用程序運行時的關鍵信息,幫助開發者在問題發生時追溯根源,在系統運行時監控狀態,甚至在安全審計時提供證據。本文將帶你深入了解C/C++日志庫的應用場景、基本實現步驟、關鍵注意事項,并推薦一些優秀的開源項目及其使用方法。

一、為什么需要日志庫?—— 應用場景探秘

想象一下,在一個漆黑的夜晚,你獨自駕駛著一輛汽車在陌生的道路上飛馳,突然儀表盤熄滅了,引擎發出了異響,你卻不知道發生了什么。日志系統就是軟件的儀表盤和傳感器,它告訴我們:

  1. 故障排查與調試 (Debugging & Troubleshooting)

    • 情感提示:當程序崩潰或行為異常時,那種抓狂和無助感是每個程序員都經歷過的。日志是你的“夏洛克·福爾摩斯”,它能提供案發現場的關鍵線索。
    • 場景:記錄關鍵變量的值、函數調用順序、錯誤碼、異常堆棧等,幫助快速定位問題。例如,線上服務突然出現大量500錯誤,通過錯誤日志可以迅速找到是哪個模塊的哪個函數調用失敗,以及失敗的原因。
  2. 運行監控與告警 (Monitoring & Alerting)

    • 情感提示:看著自己開發的系統穩定運行,就像看著孩子健康成長一樣令人欣慰。日志能讓你實時掌握系統的“健康狀況”。
    • 場景:記錄系統啟動/關閉、關鍵服務的狀態、處理請求數、響應時間、資源使用率(CPU、內存、磁盤)等。當某些指標超過閾值(如錯誤率飆升、響應時間過長),可以觸發告警通知運維人員。
  3. 用戶行為分析 (User Behavior Analysis)

    • 情感提示:了解用戶如何與你的產品互動,是優化產品、提升用戶體驗的關鍵。日志是洞察用戶心聲的窗口。
    • 場景:記錄用戶的操作路徑、功能使用頻率、在特定頁面的停留時間等。這些數據可以幫助產品經理分析用戶偏好,優化產品設計。
  4. 安全審計與合規 (Security Auditing & Compliance)

    • 情感提示:在安全事件頻發的今天,保護用戶數據和系統安全是我們的責任。日志是守護系統安全的“哨兵”。
    • 場景:記錄用戶登錄嘗試(成功/失敗)、敏感操作(如修改密碼、刪除數據)、權限變更、異常訪問等。這些日志在發生安全事件時可以用于追溯攻擊路徑,也滿足某些行業的合規性要求。
  5. 性能分析與優化 (Performance Analysis & Optimization)

    • 情感提示:追求極致性能是許多技術人的浪漫。日志可以幫助我們找到性能瓶頸,讓程序“飛”起來。
    • 場景:記錄函數執行耗時、數據庫查詢時間、網絡請求延遲等。通過分析這些耗時數據,可以找出性能瓶頸并進行針對性優化。

二、構建一個簡單的日志庫 —— 實現步驟解析

一個基礎的日志庫通常包含以下核心組件和步驟。我們將通過一個簡化的概念模型來理解其實現:

核心組件:

  • 日志級別 (Log Level):定義日志信息的重要性(如 DEBUG, INFO, WARNING, ERROR, FATAL)。
  • 日志格式化器 (Log Formatter):定義日志輸出的格式(如時間戳、級別、線程ID、文件名、行號、消息體)。
  • 日志輸出地 (Log Appender/Handler):定義日志輸出到哪里(如控制臺、文件、網絡、數據庫)。
  • 日志過濾器 (Log Filter):根據級別或其他條件決定某些日志是否需要記錄。
  • 日志記錄器 (Logger):提供給用戶調用的API接口。

實現步驟:

  1. 定義日志級別 (Log Level)

    • 通常使用枚舉類型定義,并賦予不同的嚴重程度值。
    enum LogLevel {DEBUG = 0,INFO,WARNING,ERROR,FATAL
    };
    
  2. 設計日志消息結構體/類 (Log Message)

    • 用于承載單條日志的全部信息。
    struct LogEvent {LogLevel level;long long timestamp; // e.g., milliseconds since epochunsigned int thread_id;const char* file_name;int line_number;std::string message;// ... other fields
    };
    
  3. 實現日志格式化器 (Formatter)

    • 一個函數或類,接收LogEvent對象,返回格式化后的字符串。
    • 例如,格式可以是 [YYYY-MM-DD HH:MM:SS.sss] [LEVEL] [thread_id] [file:line] message
  4. 實現日志輸出地 (Appender/Handler)

    • 控制臺輸出:使用 std::coutprintf
    • 文件輸出:使用 std::ofstream。需要考慮文件打開、寫入、關閉,以及文件滾動(按大小或時間)。
    • 異步寫入:為提高性能,通常會將日志消息放入一個隊列,由單獨的后臺線程負責實際的I/O操作。
  5. 實現日志記錄器 (Logger)

    • 提供宏或函數接口供用戶調用,如 LOG_INFO("User %s logged in.", username)
    • 內部邏輯:
      • 檢查當前設置的日志級別,如果消息級別低于設定級別,則忽略。
      • 獲取當前時間、線程ID、調用處的文件名和行號(可使用 __FILE__, __LINE__ 宏)。
      • 組裝 LogEvent 對象。
      • 調用格式化器。
      • 調用輸出地進行輸出。
  6. 配置與管理

    • 允許用戶配置最低日志級別、輸出格式、輸出目標等。
    • 可以設計一個單例的日志管理器來統一管理這些配置和Logger實例。

流程圖 (Simplified Log Flow):

graph TDA[應用程序調用日志接口 e.g., LOG_INFO("message")] --> B{日志級別判斷};B -- 滿足當前日志級別 --> C[獲取上下文信息 (時間, 線程ID, 文件, 行號)];C --> D[創建LogEvent對象];D --> E[格式化LogEvent為字符串];E --> F{選擇輸出目標 (Appender)};F -- 控制臺 --> G1[輸出到Console];F -- 文件 --> G2[輸出到File (可能涉及隊列和異步寫入)];F -- 網絡 --> G3[發送到遠程服務器];G1 --> H[完成];G2 --> H;G3 --> H;B -- 不滿足級別 --> H;

情感提示:從零開始構建一個日志庫,就像親手打造一件工具,雖然過程可能復雜,但完成后會帶來滿滿的成就感和對日志系統更深刻的理解。

三、使用日志庫的注意事項 —— 避坑指南

  1. 性能開銷 (Performance Overhead)

    • 問題:日志記錄,特別是磁盤I/O,是相對耗時的操作。過度或不當的日志記錄會嚴重影響應用程序性能。
    • 對策
      • 異步日志:將日志寫入操作放到單獨的后臺線程處理,主業務線程僅將日志消息放入隊列,避免阻塞。
      • 級別控制:生產環境通常只開啟INFO及以上級別的日志,DEBUG日志默認關閉,僅在需要時開啟。
      • 避免在熱點路徑頻繁記錄:對于調用非常頻繁的代碼路徑,謹慎添加日志。
      • 高效的格式化:避免復雜的字符串拼接,預編譯格式化字符串。
  2. 日志內容與可讀性 (Log Content & Readability)

    • 問題:日志信息不足或過于冗余,格式混亂,都會導致排查問題時效率低下。
    • 對策
      • 包含上下文:確保日志包含足夠的信息(時間戳、級別、模塊、線程ID、關鍵業務ID如訂單號、用戶ID)。
      • 結構化日志:考慮使用JSON或其他結構化格式,便于機器解析和后續的日志分析系統(如ELK Stack)處理。
      • 簡潔明了:避免打印大量無用信息,消息應直指問題核心。
      • 統一格式:團隊內或項目內應統一日志格式和規范。
  3. 日志文件管理 (Log File Management)

    • 問題:日志文件無限增長會耗盡磁盤空間。
    • 對策
      • 日志滾動 (Log Rotation):按文件大小(如每100MB一個文件)或時間(如每天一個文件)分割日志。
      • 日志清理 (Log Purging):定期刪除舊的日志文件,只保留一定時間或一定數量的日志。
  4. 線程安全 (Thread Safety)

    • 問題:在多線程環境下,多個線程同時寫入日志可能導致數據錯亂或程序崩潰。
    • 對策
      • 確保日志庫內部對共享資源(如文件句柄、內部隊列)的訪問是線程安全的(使用互斥鎖、原子操作等)。
      • 異步日志本身通過隊列解耦,有助于簡化線程安全問題。
  5. 配置靈活性 (Configuration Flexibility)

    • 問題:硬編碼日志配置(如級別、輸出目標)導致無法在運行時動態調整。
    • 對策
      • 支持通過配置文件(如INI, XML, JSON, YAML)或環境變量來設置日志參數。
      • 理想情況下,應支持運行時動態修改日志級別,而無需重啟應用。
  6. 安全性 (Security)

    • 問題:日志中可能不慎記錄了敏感信息(如密碼、身份證號、銀行卡號、密鑰)。
    • 對策
      • 數據脫敏:在記錄敏感數據前進行脫敏處理(如密碼用******替代)。
      • 代碼審查:確保日志記錄代碼不會泄露敏感信息。
      • 訪問控制:保護日志文件和日志系統的訪問權限。
  7. 避免在日志代碼中拋出異常 (No Exceptions from Logging Code)

    • 問題:如果日志庫自身發生錯誤(如磁盤滿無法寫入)并拋出異常,可能會干擾主業務邏輯,甚至導致應用崩潰。
    • 對策:日志庫應妥善處理內部錯誤,例如打印到標準錯誤流或記錄一個內部錯誤狀態,而不是向上拋出異常。

情感提示:遵循這些注意事項,就像給你的日志系統穿上“鎧甲”,讓它在服務你的同時,不會成為新的“麻煩制造者”。

四、優秀的開源C/C++日志庫推薦與使用

社區已經有很多成熟且高性能的C/C++日志庫,它們解決了上述大部分問題,通常比我們自己從零實現的更健壯、功能更豐富。

1. spdlog

  • 簡介:一個非常快速、僅頭文件(Header-only)的C++日志庫。設計簡潔,易于使用,性能極高。支持同步/異步模式、自定義格式、多種sink(輸出目標,如控制臺、文件、輪轉文件、syslog等)。
  • 特點
    • 極高的性能,低延遲。
    • 線程安全。
    • 支持多種日志級別。
    • 靈活的格式化 %v (消息), %t (線程ID), %l (級別) 等。
    • 豐富的Sink選項。
    • 僅頭文件,集成方便。
  • 使用方式 (CMake示例)
    1. 獲取:可以直接下載頭文件,或者通過Git submodule/FetchContent集成。

      # CMakeLists.txt
      cmake_minimum_required(VERSION 3.10)
      project(MyProject)set(CMAKE_CXX_STANDARD 11) # spdlog requires C++11 or laterinclude(FetchContent)
      FetchContent_Declare(spdlogGIT_REPOSITORY https://github.com/gabime/spdlog.gitGIT_TAG v1.x # Or a specific version tag like v1.12.0
      )
      FetchContent_MakeAvailable(spdlog)add_executable(MyApp main.cpp)
      target_link_libraries(MyApp PRIVATE spdlog::spdlog)
      # If using the header-only version, you might just need to include directories
      # target_include_directories(MyApp PRIVATE ${spdlog_SOURCE_DIR}/include)
      
    2. 代碼示例

      // main.cpp
      #include "spdlog/spdlog.h"
      #include "spdlog/sinks/basic_file_sink.h" // for basic file logging
      #include "spdlog/sinks/rotating_file_sink.h" // for rotating file logging
      #include "spdlog/async.h" // for async loggingvoid basic_usage() {spdlog::info("Welcome to spdlog!");spdlog::error("Some error message with arg: {}", 1);spdlog::warn("Easy padding in numbers like {:08d}", 12);spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);spdlog::info("Support for floats {:03.2f}", 1.23456);spdlog::info("Positional args are {1} {0}..", "too", "supported");spdlog::info("{:<30}", "left aligned");spdlog::set_level(spdlog::level::debug); // Set global log level to debugspdlog::debug("This message should be displayed..");    
      }void file_logger_example() {try {// Create a file logger (single file)auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");file_logger->info("This is a message to the basic file logger.");spdlog::register_logger(file_logger); // Register to use globally with spdlog::get()// Create a rotating file logger (e.g., 5MB size limit, 3 rotated files)auto rotating_logger = spdlog::rotating_logger_mt("rotating_logger", "logs/rotating.txt", 1024 * 1024 * 5, 3);rotating_logger->warn("This is a warning to the rotating file logger.");// Use a globally registered loggerspdlog::get("basic_logger")->info("Another message from global access.");} catch (const spdlog::spdlog_ex &ex) {spdlog::error("Log initialization failed: {}", ex.what());}
      }void async_logger_example() {// Default thread pool settings can be modified via spdlog::init_thread_pool()spdlog::init_thread_pool(8192, 1); // queue size of 8192 and 1 worker threadauto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");async_file->info("This is an async log message!");// ... more logsspdlog::drop_all(); // Release all loggers and flush all messages under async mode
      }int main() {// Set global pattern - [timestamp] [logger_name] [level] [thread_id] messagespdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] [thread %t] %v");spdlog::info("Application starting...");basic_usage();file_logger_example();async_logger_example(); // Make sure to call spdlog::drop_all() or let loggers go out of scope for asyncspdlog::info("Application finished.");spdlog::shutdown(); // Release all spdlog resourcesreturn 0;
      }
      

2. Glog (Google Logging Library)

  • 簡介:Google出品的C++日志庫,功能強大,廣泛應用于Google內部項目和許多開源項目中。它提供了基于命令行的標志來控制日志行為。
  • 特點
    • 級別控制(INFO, WARNING, ERROR, FATAL)。
    • FATAL日志會終止程序。
    • 條件日志:LOG_IF(INFO, condition) << "message";
    • 頻次日志:LOG_EVERY_N(INFO, 10) << "Logged every 10th occurrence";
    • 調試模式下的DLOG宏,在非調試模式下不編譯。
    • 日志輸出到文件,并根據嚴重性分文件存儲。
    • 通過命令行參數配置日志行為(如 -logtostderr, -log_dir, -v (for VLOG))。
  • 使用方式
    1. 安裝:通常通過包管理器(如apt, yum, brew)或從源碼編譯安裝。
      # Example for Ubuntu
      # sudo apt-get install libgoogle-glog-dev
      
    2. CMake集成
      # CMakeLists.txt
      cmake_minimum_required(VERSION 3.10)
      project(MyGlogApp)
      set(CMAKE_CXX_STANDARD 11)find_package(glog REQUIRED)add_executable(MyApp main_glog.cpp)
      target_link_libraries(MyApp PRIVATE glog::glog)
      
    3. 代碼示例
      // main_glog.cpp
      #include <glog/logging.h>int main(int argc, char* argv[]) {// Initialize Google's logging library.google::InitGoogleLogging(argv[0]);// Optional: configure logging flags (can also be done via command line)// FLAGS_logtostderr = 1; // Log to stderr instead of filesFLAGS_log_dir = "./glogs"; // Directory to save log filesFLAGS_minloglevel = google::INFO; // Minimum log level to recordLOG(INFO) << "Found " << google::COUNTER << " cookies"; // google::COUNTER is a simple counterLOG(WARNING) << "A warning message.";LOG(ERROR) << "An error occurred!";int num_cookies = 10;LOG_IF(INFO, num_cookies > 5) << "We have more than 5 cookies, yum!";for (int i = 0; i < 25; ++i) {LOG_EVERY_N(INFO, 5) << "Logged at iteration " << i << " (every 5th)";}// VLOG is verbose logging, controlled by -v=<level> command line flag// or FLAGS_v = <level>;FLAGS_v = 2;VLOG(1) << "This is a VLOG(1) message."; // Will be logged if -v>=1VLOG(2) << "This is a VLOG(2) message."; // Will be logged if -v>=2VLOG(3) << "This is a VLOG(3) message."; // Will NOT be logged if -v=2DLOG(INFO) << "This is a debug log, only compiled in debug mode."; // (NDEBUG not defined)// To make FATAL not abort for this example, but in real app it does.// google::InstallFailureSignalHandler(); // For better stack traces on crash// LOG(FATAL) << "A fatal error! Program will terminate."; // This would normally abort.LOG(INFO) << "Application shutting down.";google::ShutdownGoogleLogging();return 0;
      }
      
      編譯運行后,可以在 ./glogs 目錄下找到日志文件,如 MyGlogApp.INFO, MyGlogApp.WARNING 等。

3. Boost.Log

  • 簡介:Boost庫集合中的一員,功能極其強大和靈活,但配置也相對復雜。它提供了非常細致的控制,包括過濾、格式化、多種sink的組合等。
  • 特點
    • 非常全面的功能集。
    • 高度可定制的格式化和過濾。
    • 支持線程安全的異步日志。
    • 豐富的sink(文本文件、syslog、Windows事件日志、網絡等)。
  • 情感提示:Boost.Log 像是日志庫中的“瑞士軍刀”,功能強大,但可能需要更多時間來學習和掌握。對于追求極致定制化和復雜場景的項目,它是一個不錯的選擇。

五、總結與展望

日志是軟件開發中不可或缺的一環。一個好的日志系統能顯著提高開發效率、運維能力和系統的可靠性。

  • 對于初學者或中小型項目spdlog 因其易用性、高性能和僅頭文件的特性,是非常棒的選擇。
  • 對于大型項目或有特定需求(如命令行配置)的項目glog 是一個經過驗證的、可靠的選擇。
  • 對于需要高度定制化和復雜日志處理邏輯的場景Boost.Log 提供了無與倫比的靈活性。

情感提示:選擇或構建日志庫,就像為你的項目選擇一位忠實的記錄者。它默默無聞,卻在關鍵時刻為你提供最有力的支持。希望這篇博文能為你打開C/C++日志庫的大門,讓你在未來的開發旅程中,不再為“迷霧”所困,而是擁有清晰的“航行日志”,指引你乘風破浪!

不斷實踐、不斷優化你的日志策略,讓日志真正成為你項目的得力助手。祝你編碼愉快!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80296.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80296.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80296.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C 語言圖形編程 | 界面 / 動畫 / 字符特效

注&#xff1a;本文為 “C 語言圖形編程” 相關文章合輯。 略作重排&#xff0c;如有內容異常&#xff0c;請看原文。 C 語言圖形化界面——含圖形、按鈕、鼠標、進度條等部件制作&#xff08;帶詳細代碼、講解及注釋&#xff09; 非線性光學元件于 2020-02-15 09:42:37 發布…

開發狂飆VS穩定剎車:Utility Tree如何讓架構決策“快而不失控”

大家好&#xff0c;我是沛哥兒。 在軟件技術架構的世界里&#xff0c;架構師們常常面臨靈魂拷問&#xff1a;高并發和低成本哪個優先級更高&#xff1f; 功能迭代速度和系統穩定性該如何平衡&#xff1f; 當多個質量屬性相互沖突時&#xff0c;該如何做出科學決策&#xff1f; …

SCI論文圖數據提取軟件——GetData Graph Digitizer

在寫綜述或者畢業論文的時候一般會引用前人的文獻數據圖&#xff0c;但是直接截圖獲取來的數據圖通常質量都不太高。因此我們需要從新畫一張圖&#xff0c;可以通過origin繪圖來實現&#xff0c;今天介紹一個新的軟件GetData Graph Digitizer 感謝下面博主分享的破解安裝教程 …

深入探索 Apache Spark:從初識到集群運行原理

深入探索 Apache Spark&#xff1a;從初識到集群運行原理 在當今大數據時代&#xff0c;數據如同奔涌的河流&#xff0c;蘊藏著巨大的價值。如何高效地處理和分析這些海量數據&#xff0c;成為各行各業關注的焦點。Apache Spark 正是為此而生的強大引擎&#xff0c;它以其卓越…

場景可視化與數據編輯器:構建數據應用情境?

場景可視化是將數據與特定的應用場景相結合&#xff0c;借助數據編輯器對數據進行靈活處理和調整&#xff0c;通過模擬和展示真實場景&#xff0c;使企業能夠更直觀地理解數據在實際業務中的應用和影響&#xff0c;為企業的決策和運營提供有力支持。它能夠將抽象的數據轉化為具…

攻防世界-php偽協議和文件包含

fileinclude 可以看到正常回顯里面顯示lan參數有cookie值表示為language 然后進行一個判斷&#xff0c;如果參數不是等于英語&#xff0c;就加上.php&#xff0c;那我們就可以在前面進行注入一個參數&#xff0c;即flag&#xff0c; payload&#xff1a;COOKIE:languageflag …

手撕LFU

博主介紹&#xff1a;程序喵大人 35- 資深C/C/Rust/Android/iOS客戶端開發10年大廠工作經驗嵌入式/人工智能/自動駕駛/音視頻/游戲開發入門級選手《C20高級編程》《C23高級編程》等多本書籍著譯者更多原創精品文章&#xff0c;首發gzh&#xff0c;見文末&#x1f447;&#x1f…

火影bug,未保證短時間數據一致性,拿這個例子講一下Redis

本文只拿這個游戲的bug來舉例Redis&#xff0c;如果有不妥的地方&#xff0c;聯系我進行刪除 描述&#xff1a;今天在高速上打火影&#xff08;有隧道&#xff0c;有時候會卡&#xff09;&#xff0c;發現了個bug&#xff0c;我點了兩次-1000的忍玉&#xff08;大概用了1千七百…

KRaft (Kafka 4.0) 集群配置指南(超簡單,脫離 ZooKeeper 集群)還包含了簡化測試指令的腳本!!!

docker-compose方式部署kafka集群 Kafka 4.0 引入了 KRaft 模式&#xff08;Kafka Raft Metadata Mode&#xff09;&#xff0c;它使 Kafka 集群不再依賴 ZooKeeper 進行元數據管理。KRaft 模式簡化了 Kafka 部署和管理&#xff0c;不需要額外配置 ZooKeeper 服務&#xff0c;…

Admyral - 可擴展的GRC工程自動化平臺

文章目錄 一、關于 Admyral相關鏈接資源關鍵特性 二、安裝系統要求 三、快速開始1、啟動服務 四、核心功能1、自動化即代碼2、AI增強工作流3、雙向同步編輯器4、工作流監控5、企業級基礎設施 五、示例應用六、其他信息許可證遙測說明 一、關于 Admyral Admyral 是一個基于 Pyt…

DDR在PCB布局布線時的注意事項及設計要點

一、布局注意事項 控制器與DDR顆粒的布局 靠近原則&#xff1a;控制器與DDR顆粒應盡量靠近&#xff0c;縮短時鐘&#xff08;CLK&#xff09;、地址/控制線&#xff08;CA&#xff09;、數據線&#xff08;DQ/DQS&#xff09;的走線長度&#xff0c;減少信號延遲差異。 分組隔…

計算機網絡-LDP工作過程詳解

前面我們已經學習了LDP的基礎概念&#xff0c;了解了LDP會話的建立、LDP的標簽控制等知識&#xff0c;今天來整體過一遍LDP的一個工作過程&#xff0c;后面我們再通過實驗深入學習。 一、LDP標簽分發 標簽分發需要基于基礎的路由協議建立LDP會話&#xff0c;激活MPLS和LDP。以…

解構與重構:自動化測試框架的進階認知之旅

目錄 一、自動化測試的介紹 &#xff08;一&#xff09;自動化測試的起源與發展 &#xff08;二&#xff09;自動化測試的定義與目標 &#xff08;三&#xff09;自動化測試的適用場景 二、什么是自動化測試框架 &#xff08;一&#xff09;自動化測試框架的定義 &#x…

跑不出的循環 | LoveySelf 系列定位

最近開始陷入一輪一輪的循環狀態&#xff0c;無奈&#xff0c;只能自我整理一下。23年暑假&#xff0c;在計算機系折騰了一年后&#xff0c;重新打開博客&#xff0c;回想在數學系摸索博客寫作的日子&#xff0c;思緒涌上心頭&#xff0c;我們決定拾起這份力量。當時覺得 hexo …

Redis最新入門教程

文章目錄 Redis最新入門教程1.安裝Redis2.連接Redis3.Redis環境變量配置4.入門Redis4.1 Redis的數據結構4.2 Redis的Key4.3 Redis-String4.4 Redis-Hash4.5 Redis-List4.6 Redis-Set4.7 Redis-Zset 5.在Java中使用Redis6.緩存雪崩、擊穿、穿透6.1 緩存雪崩6.2 緩沖擊穿6.3 緩沖…

一文讀懂Python之requests模塊(36)

一、requests模塊簡介 requests模塊是python中原生的一款基于網絡請求的模塊&#xff0c;功能強大&#xff0c;簡單便捷且高效 &#xff0c;該模塊可以模擬瀏覽器發送請求&#xff0c;主要包括指定url、發起請求、獲取響應數據和持久化存儲&#xff0c;包括 GET、POST、PUT、…

WPF之布局流程

文章目錄 1. 概述2. 布局元素的邊界框3. 布局系統原理3.1 布局流程時序圖 4. 測量階段(Measure Phase)4.1 測量過程4.2 MeasureOverride方法 5. 排列階段(Arrange Phase)5.1 排列過程5.2 ArrangeOverride方法 6. 渲染階段(Render Phase)7. 布局事件7.1 主要布局事件7.2 布局事件…

uniapp|獲取當前用戶定位、與系統設定位置計算相隔米數、實現打卡簽到(可自定義設定位置、位置有效范圍米數)

基于UniApp闡述移動應用開發中定位功能的實現全流程,涵蓋實時定位獲取、動態距離計算與自定義位置、有效范圍設定等功能。文章提供完整的代碼示例與適配方案,適用于社交簽到、課堂教室打卡等場景。 目錄 引言定位功能在移動應用中的價值(社交、導航、O2O等場景)UniApp跨平臺…

Yii2.0 模型規則(rules)詳解

一、基本語法結構 public function rules() {return [// 規則1[[attribute1, attribute2], validator, options > value, ...],// 規則2[attribute, validator, options > value, ...],// 規則3...]; }二、規則類型分類 1、核心驗證器&#xff08;內置驗證器&#xff0…

數據結構(三)——棧和隊列

一、棧和隊列的定義和特點 棧&#xff1a;受約束的線性表&#xff0c;只允許棧頂元素入棧和出棧 對棧來說&#xff0c;表尾端稱為棧頂&#xff0c;表頭端稱為棧底&#xff0c;不含元素的空表稱為空棧 先進后出&#xff0c;后進先出 隊列&#xff1a;受約束的線性表&#xff0…