跟我學c++中級篇——多線程中的文件處理

一、文件處理

作為IO處理的一種重要場景,文件處理是幾乎所有編程都無法繞過的一個情況。稍微復雜的一些的程序都可能需要文件處理,不管這種文件處理對開發者來說是顯式的還是隱式的。相對于其它語言,C++并未提供多么好的文件處理API接口,即使發展到現在,C++新標準的文件處理,相比與C#等語言處理起文件的方式仍然要落后不少。
文件處理相對來說的復雜再加上C++中線程管理的復雜,二者結合到一起,就會產生各種大大小小的問題。

二、多線程與資源控制

其實對開發者來說,不管是文件管理還是其它資源管理,最主要的就是在多線程的切換中,保持安全性(不能崩潰)、數據的準確性(不能寫得不對)。在這些基礎上,如何提高資源處理的速度并按照開發者既定的意愿去完成相關的資源控制,這才是難點所在。
特別在一些具體的場景中,如大文件(海量日志文件)、數據庫操作以及圖像視頻等的處理,這都需要多線程參與下的高效率的處理。在前面學習多線程時知道對資源的控制一般有幾種處理方法:
1、使用鎖
這里的鎖,包括各種的互斥體和信號量等
2、使用原子變量
其實,使用原子變量的目的也類似于鎖
3、使用無鎖編程
這個就相對復雜很多,而且適用場景也受限

三、多線程條件下的文件處理方法

上面的這些方法對于所有的資源控制都是行之有效的,但針對文件處理,可能一些更具體的方法。對于文件來說,需要處理兩種情況即:
1、文件的寫
文件的寫是一種常見的保存數據的方法,數據庫的寫其實也一種文件的寫,只不過,上面又抽象了一層數據庫的相關操作。對于寫文件來說,最基礎的是寫入的完整性、一致性,最重要的是寫入的速度。
多線程的寫入,往往因為同步的問題,引起以下的情況:
a)由于無法同步導致的問題
包括數據寫入順序不一致引起的數據覆蓋以及數據順序的不正確,導致數據的完整性的缺損,從而最終導致文件可能無法打開
b)因為同步導致寫入效率的問題
多線程的情況下,不適當的同步,或者說即使是適當的同步,也會大幅的降低寫文件的速度
c)引入異步IO導致的編程復雜性
異步IO的操作本身就是一個難點,這對于很多開發者說,掌握的都不是很到位
d)是否使用寫緩沖
其實在很多情況,特別是在多線程的情況下,往往會把并發寫轉成串行寫,數據量的增加往往要求引入緩沖區
總之,寫文件,是多線程操作中相對復雜和困難的情況。
寫文件有幾種情況比較特殊,一種是寫入大量的小文件,這種情況在互聯網中特別常見,比如大量的商品的縮略圖;另外一種是寫一個非常大的文件,如日志;另外還有大家常見的如BT等下載軟件,多線程分段下載然后最終再組成一個大文件(分塊處理)。

2、文件的讀
文件的讀相對寫來說應用場景更豐富,在互聯網中針對文件讀還專門有各種的優化方法。比如各種緩沖、臨時文件等等。
多線程情況下的文件讀其實有很多種方法,來適應不同的場景:
a)使用緩沖
這種緩沖既包括硬件本身的緩沖也包括軟件層次的緩沖,甚至是框架之間的緩沖,如使用內存型數據庫(如Redis)+傳統的數據庫(如MySql),前者就可以作為后者的緩沖。而在C++編程中也提供了iosteam的緩沖的控制。其它的一些系統API和庫的API也多少都提供了類似的功能。
b)使用異步IO
異步IO的問題主要就在于異步編程的復雜度,這里不再贅述
c)多線程讀取的時效問題
也就是常見的讀寫同時在進行時,如何保證讀的時效性(即盡可能減少臟讀),特別是在分布式、多線程的情況下。

四、典型的文件處理方式

內存緩沖區 使用新的異步框架 或新技術
典型的文件處理方式一般有以下幾種處理方法:
1、使用內存映射
這個在操作一些大的日志文件時,經常使用這種內存映射,從而快速讀寫日志。
2、使用緩沖
包括前面提到的軟件層次的緩沖、硬件緩沖及內核緩沖等。
3、使用最新的框架或技術
比如前文“Linux新的IO模型io_uring”提到的io_uring以及其它的新技術、新框架甚至是新思想,來解決某些對文件操作極度嚴苛的場景。
4、使用合理的策略
這個就比較靈活了,比如上面提到的大文件的多線程下載,就可以使用合理的策略來進行分塊然后再進行傳輸、驗證、組合等等。另外在數據庫讀寫中,面對大量的寫可以使用批處理,而使用緩沖時,可以在大多數場景下指定臨界值再進行真正的寫入等等。
5、多線程的合理控制
無論何種情況,只要發生在了多線程并發或并行的場景下,合理調試線程和分配任務就是一種高優先級的考慮方向了。也可以這樣認為,面對復雜的文件處理,不是某一層可以解決的,它是從上到下,從里到外,一個綜合應用的場景。

五、實際的例子

下面級出一個大日志文件使用內存映射操作的例程:

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <system_error>class MemMappedFile {
public:explicit MemMappedFile(const std::string& path, bool enable = false) {// 打開文件int flags = enable ? O_RDWR : O_RDONLY;m_fd = open(path.c_str(), flags);if (m_fd == -1) {return;}// 獲取映射文件大小struct stat sb;if (fstat(m_fd, &sb) == -1) {close(m_fd);return ;}m_size = sb.st_size;// 創建內存映射int prot = PROT_READ | (enable ? PROT_WRITE : 0);m_data = mmap(nullptr, m_size, prot, MAP_SHARED, m_fd, 0);if (m_data == MAP_FAILED) {close(m_fd);return;}}~MemMappedFile() {if (m_data != nullptr) {munmap(m_data, m_size);}if (m_fd != -1) {close(m_fd);}}MemMappedFile(const MemMappedFile&) = delete;MemMappedFile& operator=(const MemMappedFile&) = delete;
public:char* data() const { return static_cast<char*>(m_data); }size_t size() const { return m_size; }// 同步修改到磁盤void syncToDisk() {if (msync(m_data, m_size, MS_SYNC) == -1) {return;}}private:int m_fd = -1;void* m_data = nullptr;size_t m_size = 0;
};
// 處理數據
void processData(const char* chunk, size_t  size) {// 日志處理,略過
}
int main(int argc, char* argv[]) {if (argc < 2) {std::cerr << "cur use: " << argv[0] << std::endl;return 1;}try {//創建映射bool enable = (argc >= 3);MemMappedFile mmapFile(argv[1], enable);const char* data = mmapFile.data();size_t size = mmapFile.size();size_t lineCount = 0;size_t errNum = 0;const char* keyword = "ERR";for (size_t i = 0; i < size; ++i) {if (data[i] == '\n') {lineCount++;}if (strncmp(&data[i], keyword, strlen(keyword)) == 0) {errNum++;i += strlen(keyword) - 1;}}std::cout << "lines is: " << lineCount<< "errors is: " << errNum  << std::endl;if (enable) {const char* newHeader = "start modify log...\n";size_t headerLen = strlen(newHeader);if (size >= headerLen) {memcpy(mmapFile.data(), newHeader, headerLen);mmapFile.syncToDisk();}}//分塊處理const size_t chunkSize = 1024 * 1024;for (size_t offset = 0; offset < size; offset += chunkSize) {size_t chunkLen = std::min(chunkSize, size - offset);processData(data + offset, chunkLen);}} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}return 0;
}

注釋已經很清晰,大家可以參考一下。

六、總結

多線程下的文件處理,需要整合前面學習的很多知識點。大家不用把它想象的多么難,重點在于分析實際的應用場景,找出一個合適的解決方案就可以了。不是每個開發者都會遇到海量的數據讀寫。但掌握一些海量數據下的文件處理的經驗卻是非常必要的。

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

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

相關文章

Flutter知識點匯總

Flutter架構解析 1. Flutter 是什么?它與其他移動開發框架有什么不同? Flutter 是 Google 開發的開源移動應用開發框架,可用于快速構建高性能、高保真的移動應用(iOS 和 Android),也支持 Web、桌面和嵌入式設備。。它與其他移動開發框架(如 React Native、Xamarin、原…

【會員專享數據】1980—2022年中國逐日月年潛在蒸散發柵格數據

氣象數據是我們在各項研究中都經常使用的數據&#xff0c;尤其是高精度的氣象數據應用價值非常高。 之前我們分享過研究者張凌, 胡英屹等發布在國家冰川凍土沙漠科學數據中心平臺上的nc格式的1980—2022年中國高分辨率逐日、逐月、逐年氣象數據&#xff01;很多小伙伴拿到數據…

前端打包工具簡單介紹

前端打包工具簡單介紹 一、Webpack 架構與插件機制 1. Webpack 架構核心組成 Entry&#xff08;入口&#xff09; 指定應用的起點文件&#xff0c;比如 src/index.js。 Module&#xff08;模塊&#xff09; Webpack 把項目當作模塊圖&#xff0c;模塊可以是 JS、CSS、圖片等…

工業控制核心引擎高性能MCU——MM32F5370

RAMSUN提供的MM32F5370搭載180MHz Arm China Star-MC1處理器&#xff0c;集成DSP、FPU與三角函數加速單元&#xff08;CORDIC&#xff09;&#xff0c;輕松應對復雜算法需求。其技術亮點包括&#xff1a; 超高精度PWM&#xff1a;8通道208ps級高精度PWM輸出&#xff0c;滿足儲能…

AI架構師修煉之道

1 AI時代的架構革命 與傳統軟件開發和軟件架構師相比&#xff0c;AI架構師面臨著三重范式轉換&#xff1a; 1.1 技術維度&#xff0c;需處理異構算力調度與模型生命周期管理的復雜性&#xff1b; 1.2 系統維度&#xff0c;需平衡實時性與資源約束的矛盾&#xff1b; 1.3 價…

數學建模期末速成 主成分分析的基本步驟

設有 n n n個研究對象&#xff0c; m m m個指標變量 x 1 , x 2 , ? , x m x_1,x_2,\cdots,x_m x1?,x2?,?,xm?&#xff0c;第 i i i個對象關于第 j j j個指標取值為 a i j a_{ij} aij?,構造數據矩陣 A ( a i j ) n m A\left(\begin{array}{c}a_{ij}\end{array}\right)_{…

博圖 SCL 編程技巧:靈活實現上升沿與下降沿檢測案例分享(上)

博圖 SCL 編程技巧&#xff1a;靈活實現上升沿與下降沿檢測案例分享 在 PLC 編程中&#xff0c;檢測信號從 0 變為 1 (上升沿) 或從 1 變為 0 (下降沿) 是最基礎也是最關鍵的操作之一。它常用于啟動單次動作、計數、狀態切換等場景。在西門子 TIA Portal 環境中&#xff0c;雖…

深度學習入門Day3--魚書學習(2)

這倆天剛忙完答辯的事情&#xff0c;終于有時間學習了 一、3層神經網絡實現 1.本節中的符號使用說明。 w 12 ( 1 ) w_{12}^{(1)} w12(1)?表示前一層的第2個神經元 x 2 x_{2} x2?到后一層的第一個神經元 a 1 a_{1} a1?的權重。權重右下角按照“后一層的索引號、前一層的索引…

服務器 | Centos 9 系統中,如何部署SpringBoot后端項目?

系列文章目錄 虛擬機 | Ubuntu 安裝流程以及界面太小問題解決 虛擬機 | Ubuntu圖形化系統&#xff1a; open-vm-tools安裝失敗以及實現文件拖放 虛擬機 | Ubuntu操作系統&#xff1a;su和sudo理解及如何處理忘記root密碼 文章目錄 系列文章目錄前言一、環境介紹二、 使用syst…

CNN核心機制深度解析:卷積池化原理 PyTorch實現經典網絡

本文較長&#xff0c;建議點贊收藏&#xff0c;以免遺失。更多AI大模型應用開發學習視頻及資料&#xff0c;盡在聚客AI學院。 本文系統講解CNN核心原理、經典網絡架構和圖像分類實戰&#xff0c;涵蓋卷積層、池化層、LeNet/AlexNet/VGG/ResNet設計思想&#xff0c;并提供CIFAR-…

6個月Python學習計劃 Day 17 - 繼承、多態與魔術方法

第三周 Day 4 &#x1f3af; 今日目標 理解類的繼承和方法重寫掌握多態思想及其實際應用了解并使用常見的魔術方法&#xff08;如 str、len 等&#xff09; &#x1f9ec; 類的繼承&#xff08;Inheritance&#xff09; Python 支持單繼承與多繼承&#xff0c;常用語法如下&…

抖音怎么下載視頻

抖音作為一款短視頻社交平臺&#xff0c;憑借其獨特的短視頻形式和豐富的內容&#xff0c;吸引了大量用戶。有些用戶在欣賞完抖音視頻后&#xff0c;想要將其保存下來&#xff0c;以便日后觀看。如何在抖音下載視頻呢&#xff1f;本文將為您詳細介紹抖音視頻下載的技巧和方法。…

使用MinIO搭建自己的分布式文件存儲

目錄 引言&#xff1a; 一.什么是 MinIO &#xff1f; 二.MinIO 的安裝與部署&#xff1a; 三.Spring Cloud 集成 MinIO&#xff1a; 1.前提準備&#xff1a; &#xff08;1&#xff09;安裝依賴&#xff1a; &#xff08;2&#xff09;配置MinIO連接&#xff1a; &…

uni-app 如何實現選擇和上傳非圖像、視頻文件?

在 uni-app 中實現選擇和上傳非圖像、視頻文件&#xff0c;可根據不同端&#xff08;App、H5、小程序&#xff09;的特點&#xff0c;采用以下方法&#xff1a; 一、通用思路&#xff08;多端適配優先推薦&#xff09; 借助 uni.chooseFile 選擇文件&#xff0c;再用 uni.upl…

正點原子[第三期]Arm(iMX6U)Linux移植學習筆記-12.1 Linux內核啟動流程簡介

前言&#xff1a; 本文是根據嗶哩嗶哩網站上“Arm(iMX6U)Linux系統移植和根文件系統構鍵篇”視頻的學習筆記&#xff0c;在這里會記錄下正點原子 I.MX6ULL 開發板的配套視頻教程所作的實驗和學習筆記內容。本文大量引用了正點原子教學視頻和鏈接中的內容。 引用&#xff1a; …

UDP與TCP通信協議技術解析

文章目錄 協議基礎原理TCP&#xff1a;可靠的面向連接通信UDP&#xff1a;高效的無連接通信 性能特征分析TCP性能表現UDP性能表現 應用場景分析TCP適用場景UDP適用場景 技術實現考量錯誤處理策略網絡資源利用 選擇決策框架可靠性需求評估性能要求分析 混合方案設計協議組合策略…

mysql 頁的理解和實際分析

目錄 頁&#xff08;Page&#xff09;是 Innodb 存儲引擎用于管理數據的最小磁盤單位B樹的一般高度記錄在頁中的存儲 innodb ibd文件innodb 頁類型分析ibd文件查看數據表的行格式查看ibd文件 分析 ibd的第4個頁&#xff1a;B-tree Node類型先分析File Header(38字節-描述頁信息…

【優選算法】C++滑動窗口

1、長度最小的子數組 思路&#xff1a; class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {// 滑動窗口// 1.left0,right0// 2.進窗口( nums[right])// 3.判斷// 出窗口// (4.更新結果)// 總和大于等于 target 的長度最小的 子數組…

ffmpeg(四):濾鏡命令

FFmpeg 的濾鏡命令是用于音視頻處理中的強大工具&#xff0c;可以完成剪裁、縮放、加水印、調色、合成、旋轉、模糊、疊加字幕等復雜的操作。其核心語法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "濾鏡參數" output.mp4或者帶音頻濾鏡&#xff1a; ffmpeg…

408考研逐題詳解:2009年第33題

2009年第33題 在 OSI 參考模型中&#xff0c;自下而上第一個提供端到端服務的層次是&#xff08; &#xff09; A. 數據鏈路層 \qquad B. 傳輸層 \qquad C. 會話層 \qquad D.應用層 解析 本題主要考查 OSI 參考模型各層的核心功能、端到端服務的定義。 OSI 參考模型&am…