在實(shí)際開(kāi)發(fā)過(guò)程中,我們可能會(huì)遇到并發(fā)寫(xiě)文件的場(chǎng)景,如果處理不當(dāng)很可能出現(xiàn)文件內(nèi)容亂序問(wèn)題。下面我們通過(guò)一個(gè)示例程序描述這一過(guò)程并給出解決該問(wèn)題的方法。
use std::{ fs::{self, File, OpenOptions}, io::{Write}, sync::Arc, time::{SystemTime, UNIX_EPOCH}, }; use tokio::JoinSet; fn main() { println!("parallel write file!"); let max_tasks = 200; let _ = fs::remove_file("/tmp/parallel"); let file_ref = OpenOptions::new() .create(true) .write(true) .append(true) .open("/tmp/parallel") .unwrap(); let mut set: JoinSet<()> = JoinSet::new(); let rt = tokio::new().unwrap(); rt.block_on(async { loop { while set.len() >= max_tasks { set.join_next().await; } 未做寫(xiě)互斥函數(shù) let mut file_ref = OpenOptions::new() .create(true) .write(true) .append(true) .open("/tmp/parallel") .unwrap(); set.spawn(async move { write_line(&mut file_ref) }); } }); } fn write_line(file: &mut File) { for i in 0..1000 { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); let mut content = now.as_secs().to_string(); content.push_str("_"); content.push_str(&i.to_string()); file.write_all(content.as_bytes()).unwrap(); file.write_all(" ".as_bytes()).unwrap(); file.write_all(" ".as_bytes()).unwrap(); } }
代碼不復(fù)雜,tokio 實(shí)現(xiàn)一個(gè)并發(fā)runtime,寫(xiě)文件函數(shù)是直接寫(xiě)時(shí)間戳,為了方便展示亂序所以寫(xiě)入兩次換行。
輸出的文本大概長(zhǎng)這樣:
1691287258_979 1691287258_7931691287258_301 1691287258_7431691287258_603 1691287258_8941691287258_47 1691287258_895 1691287258_553 1691287258_950 1691287258_980 1691287258_48 1691287258_302 1691287258_896 1691287258_744 1691287258_6041691287258_554
很明顯,寫(xiě)入并未達(dá)到預(yù)期,間隔并不平均,函數(shù)內(nèi)部的執(zhí)行步驟是亂序的。
我們把上面的程序改造一下:
use std::{ fs::{self, File, OpenOptions}, io::Write, sync::Arc, time::{SystemTime, UNIX_EPOCH}, }; use tokio::Mutex; use tokio::JoinSet; fn main() { println!("parallel write file!"); let max_tasks = 200; let _ = fs::remove_file("/tmp/parallel"); let file_ref = OpenOptions::new() .create(true) .write(true) .append(true) .open("/tmp/parallel") .unwrap(); let f = Arc::new(Mutex::new(file_ref)); let mut set: JoinSet<()> = JoinSet::new(); let rt = tokio::new().unwrap(); rt.block_on(async { loop { while set.len() >= max_tasks { set.join_next().await; } let mut file = Arc::clone(&f); set.spawn(async move { write_line_mutex(&mut file).await }); } }); } async fn write_line_mutex(mutex_file: &Arc>) { for i in 0..1000 { let mut f = mutex_file.lock().await; let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); let mut content = now.as_secs().to_string(); content.push_str("_"); content.push_str(&i.to_string()); f.write_all(content.as_bytes()).unwrap(); f.write_all(" ".as_bytes()).unwrap(); f.write_all(" ".as_bytes()).unwrap(); } }
這次我們用到了tokio::Mutex,write_line_mutex函數(shù)在每次執(zhí)行寫(xiě)任務(wù)以前先獲取文件互斥鎖。
看看這次的文件內(nèi)容:
1691288040_374 1691288040_374 1691288040_374 1691288040_375 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_374 1691288040_375 1691288040_375 1691288040_374 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375 1691288040_375
寫(xiě)入的格式正確,保證每次函數(shù)寫(xiě)函數(shù)完整執(zhí)行。
關(guān)于文件寫(xiě)互斥這點(diǎn)事兒,今兒就聊到這。
審核編輯:劉清
-
Unix系統(tǒng)
+關(guān)注
關(guān)注
0文章
15瀏覽量
9690 -
ARC
+關(guān)注
關(guān)注
0文章
42瀏覽量
16574 -
rust語(yǔ)言
+關(guān)注
關(guān)注
0文章
57瀏覽量
3031
原文標(biāo)題:文盤(pán)Rust -- Mutex解決并發(fā)寫(xiě)文件亂序問(wèn)題
文章出處:【微信號(hào):Rust語(yǔ)言中文社區(qū),微信公眾號(hào):Rust語(yǔ)言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
詳解linux內(nèi)核中的mutex同步機(jī)制
![詳解linux內(nèi)核中的<b class='flag-5'>mutex</b>同步機(jī)制](https://file.elecfans.com//web2/M00/43/45/pYYBAGJ9A_iAVeCiAAAWi6LW7OU907.png)
Linux內(nèi)核同步機(jī)制mutex詳解
Raw-os mutex 篇
關(guān)于mutex 鎖
labview寫(xiě)入access數(shù)據(jù)庫(kù)亂序問(wèn)題
STM32G473是如何利用DMA接收并發(fā)送數(shù)據(jù)的
互斥量Mutex相關(guān)資料推薦
適用于IPTV大并發(fā)應(yīng)用的文件格式
如何采用DATA進(jìn)行Flash的在線燒寫(xiě)
![如何采用DATA進(jìn)行Flash的在線燒<b class='flag-5'>寫(xiě)</b>](https://file.elecfans.com/web1/M00/62/7D/pIYBAFuJmTGAG-P7AAA3vUmBnrQ082.jpg)
Linux多線程同步互斥量Mutex詳解
ThreadX(七)------互斥量Mutex
![ThreadX(七)------互斥量<b class='flag-5'>Mutex</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
如何用Actix去寫(xiě)一個(gè)類(lèi)似于Facemash的小項(xiàng)目呢
![如何用Actix去<b class='flag-5'>寫(xiě)</b>一個(gè)類(lèi)似于Facemash的小項(xiàng)目呢](https://file.elecfans.com/web2/M00/70/5C/poYBAGNMtIaAIpwlAADdczQJ8JU085.jpg)
編譯器的亂序策略
![編譯器的<b class='flag-5'>亂序</b>策略](https://file1.elecfans.com/web2/M00/88/75/wKgZomRnG0yAOpR0AAAT3JZFhJ8890.jpg)
亂序文件如何重新命名編號(hào)
![<b class='flag-5'>亂序文件</b>如何重新命名編號(hào)](https://file1.elecfans.com/web2/M00/AB/61/wKgZomUzPHeAJ9xMAAASMhoGxiM107.jpg)
評(píng)論