You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否同时多次调用WriteAsync?文件写入位置竞态问题探讨

并行调用FileStream.WriteAsync的潜在问题

我想要实现如下操作:

byte[] b1,b2,b3,...
task1=fs.WriteAsync(b1, 0, b1.Length);
task2=fs.WriteAsync(b2, 0, b2.Length);
task3=fs.WriteAsync(b3, 0, b3.Length);
...
Task.WaitAll(task1,task2,task3,...)

不过我认为这存在问题,除非fs处于追加模式。这完全取决于WriteAsync是在返回任务之前还是之后更新文件位置。

情况1:WriteAsync在等待系统调用前更新文件指针

如果它在等待系统调用前就更新文件指针,比如旧版WriteAsync的伪代码:

async ValueTask WriteAsyncBefore(ReadOnlyMemory<byte> buffer)
{
    long oldEndOfFile = GetFileLength(_handle); // 第1次系统调用
    long newEndOfFile = _position + buffer.Length;

    if (newEndOfFile > oldEndOfFile) // 对空文件的每次写入都成立
    {
        ExtendTheFile(_handle, newEndOfFile); // 第2次系统调用

        SetFilePosition(_handle, newEndOfFile); // 第3次系统调用
        _position += buffer.Length;
    }

    await WriteFile(_handle, buffer); // 第4次系统调用
}

这种情况下不会有问题,因为每个WriteAsync都能使用前一个已正确累加的位置。

情况2:WriteAsync在WriteFile之后修改文件位置

但更可能的情况是WriteAsync在WriteFile之后修改文件位置,这会导致竞态条件,比如新版WriteAsync:

async ValueTask WriteAsyncAfter(ReadOnlyMemory<byte> buffer)
{
    await WriteFile(_handle, buffer, _position); // 唯一的系统调用
    _position += buffer.Length;
}

手动设置文件位置也无法解决问题

手动设置文件位置也无济于事:

pos=0;
fs.Seek(pos,Begin);
task1=fs.WriteAsync(b1, 0, b1.Length);
pos+=b1.Length;
fs.Seek(pos,Begin);
// 如果之前的WriteAsync此时完成并修改了文件位置怎么办?
task2=fs.WriteAsync(b2, 0, b2.Length);
pos+=b2.Length;
fs.Seek(pos,Begin);
// 同样的问题
task3=fs.WriteAsync(b3, 0, b3.Length);

内容的提问来源于stack exchange,提问作者elflyao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:25:09