在实际开发过程中,我们可能会遇到并发写文件的场景,如果处理不当很可能出现文件内容乱序问题。下面我们通过一个示例程序描述这一过程并给出解决该问题的方法。

use std::{
fs::{self, File, OpenOptions},
io::{Write},
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
use tokio::task::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::runtime::Runtime::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("\n".as_bytes()).unwrap();
file.write_all("\n".as_bytes()).unwrap();
}
}

代码不复杂,tokio 实现一个并发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

很明显,写入并未达到预期,间隔并不平均,函数内部的执行步骤是乱序的。

我们把上面的程序改造一下

use std::{
fs::{self, File, OpenOptions},
io::Write,
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
use tokio::sync::Mutex;
use tokio::task::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::runtime::Runtime::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<Mutex<File>>) {
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("\n".as_bytes()).unwrap();
f.write_all("\n".as_bytes()).unwrap();
}
}

这次我们用到了tokio::sync::Mutex,write_line_mutex函数在每次执行写任务以前先获取文件互斥锁。

看看这次的文件内容

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

写入的格式正确,保证每次函数写函数完整执行。

关于文件写互斥这点事儿,今儿就聊到这。

完整源码

作者:京东科技 贾世闻

来源:京东云开发者社区

文盘Rust -- Mutex解决并发写文件乱序问题的更多相关文章

  1. Python中,os.listdir遍历纯数字文件乱序如何解决

    Python中,os.listdir遍历纯数字文件乱序如何解决 日常跑深度学习视觉相关代码时,常常需要对数据集进行处理.许多图像文件名是利用纯数字递增的方式命名.通常所用的排序函数sort(),是按照 ...

  2. Python3并发写文件

    使用python2在进行并发写的时候,发现文件会乱掉,就是某一行中间会插入其他行的内容. 但是在使用python3进行并发写的时候,无论是多进程,还是多线程,都没有出现这个问题,难道是python3的 ...

  3. 文盘Rust -- 把程序作为守护进程启动

    当我们写完一个服务端程序,需要上线部署的时候,或多或少都会和操作系统的守护进程打交道,毕竟谁也不希望shell关闭既停服.今天我们就来聊聊这个事儿. 最早大家部署应用的通常操作是 "nohu ...

  4. 文盘Rust -- 本地库引发的依赖冲突

    作者:京东科技 贾世闻 问题描述 clickhouse 的原生 rust 客户端目前比较好的有两个clickhouse-rs 和 clickhouse.rs .clickhouse-rs 是 tcp ...

  5. 文盘Rust -- struct 中的生命周期

    最近在用rust 写一个redis的数据校验工具.redis-rs中具备 redis::ConnectionLike trait,借助它可以较好的来抽象校验过程.在开发中,不免要定义struct 中的 ...

  6. 文盘Rust -- 给程序加个日志

    作者:贾世闻 日志是应用程序的重要组成部分.无论是服务端程序还是客户端程序都需要日志做为错误输出或者业务记录.在这篇文章中,我们结合[log4rs](https://github.com/estk/l ...

  7. 文盘Rust -- rust 连接云上数仓 starwift

    作者:京东云 贾世闻 最近想看看 rust 如何集成 clickhouse,又犯了好吃懒做的心理(不想自己建环境),刚好京东云发布了兼容ck 的云原生数仓 Starwfit,于是搞了个实例折腾一番. ...

  8. 文盘Rust -- 用Tokio实现简易任务池

    作者:京东科技 贾世闻 Tokio 无疑是 Rust 世界中最优秀的异步Runtime实现.非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能. 我们看看下 ...

  9. 解决靶机Bee-Box 键盘乱序问题

    Bee-Box介绍 Bee-box官方称呼BWAPP,buggy web Application 这是一个集成了各种常见漏洞和最新漏洞的开源Web应用程序,目的是帮助网络安全爱好者.开发人员和学生发现 ...

  10. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

随机推荐

  1. I2C总线 | I2C总线介绍

    I2C总线 | I2C总线介绍 目录 I2C总线 | I2C总线介绍 I2C总线介绍 I2C有如下特点: I2C总线术语 I2C总线位传输 IIC总线数据传输 1.字节格式 2.应答响应 IIC总线寻 ...

  2. 2022-07-14:以下go语言代码输出什么?A:1;B:3;C:4;D:编译错误。 package main import ( “fmt“ ) func main() { a

    2022-07-14:以下go语言代码输出什么?A:1:B:3:C:4:D:编译错误. package main import ( "fmt" ) func main() { a ...

  3. 2022-03-11:int n, int[][] roads, int x, int y, n表示城市数量,城市编号0~n-1, roads[i][j] == distance,表示城市i到城市j距

    2022-03-11:int n, int[][] roads, int x, int y, n表示城市数量,城市编号0~n-1, roads[i][j] == distance,表示城市i到城市j距 ...

  4. 2021-05-26:给定一个char[][] matrix

    2021-05-26:给定一个char[][] matrix,也就是char类型的二维数组,再给定一个字符串word,可以从任何一个某个位置出发,可以走上下左右,能不能找到word?char[][] ...

  5. Jenkins - 安装部署

    Jenkins安装部署 简介 Jenkins是一个开源的软件项目,是基于java开发的一种持续集成工具,用于监控持续重复的工作,提供一个开放易用的软件平台,使软件的持续集成变成可能. 主要用于: 持续 ...

  6. 使用 Django 集成 vue 到一个服务器上,还是 Django 和 vue 分开部署

    Django+Vue 的项目,实际部署的时候,使用 Django 集成 vue 到一个服务器上,还是 Django 和 vue 分开部署? 目前在架构选择,基本上定了 Django + Vue 但是实 ...

  7. Netty实战(二)

    一.环境准备 Netty需要的运行环境很简单,只有2个. JDK 1.8+ Apache Maven 3.3.9+ 二.Netty 客户端/服务器概览 如图,展示了一个我们将要编写的 Echo 客户端 ...

  8. 源码解析:django的CSRF认证

    详解Django的CSRF认证 1.csrf原理 csrf要求发送post,put或delete请求的时候,是先以get方式发送请求,服务端响应时会分配一个随机字符串给客户端,客户端第二次发送post ...

  9. defcon-quals 2023 crackme.tscript.dso wp

    队友找到的引擎TorqueGameEngines/Torque3D (github.com) 将dso文件放到data/ExampleModule目录下,编辑ExampleModule.tscript ...

  10. Django认证流程源码及自定义 Backend

    Django自己的认证方法只能认证用户名和密码 user = authenticate(**credentials) # authenticate会自动校验用户名和密码 authenticate 源码 ...