在實際開發(fā)過程中,我們可能會遇到并發(fā)寫文件的場景,如果處理不當很可能出現文件內容亂序問題。下面我們通過一個示例程序描述這一過程并給出解決該問題的方法。
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; } 未做寫互斥函數 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(); } }
代碼不復雜,tokio 實現一個并發(fā)runtime,寫文件函數是直接寫時間戳,為了方便展示亂序所以寫入兩次換行。
輸出的文本大概長這樣:
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
很明顯,寫入并未達到預期,間隔并不平均,函數內部的執(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函數在每次執(zhí)行寫任務以前先獲取文件互斥鎖。
看看這次的文件內容:
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
寫入的格式正確,保證每次函數寫函數完整執(zhí)行。
關于文件寫互斥這點事兒,今兒就聊到這。
審核編輯:劉清
-
Unix系統(tǒng)
+關注
關注
0文章
15瀏覽量
9634 -
ARC
+關注
關注
0文章
42瀏覽量
16460 -
rust語言
+關注
關注
0文章
57瀏覽量
3006
原文標題:文盤Rust -- Mutex解決并發(fā)寫文件亂序問題
文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論