Sim*_*mon 4 c# asynchronous filestream async-await
我正在录制视频流到磁盘.为此,我使用以下代码:
private async Task SaveToFile(IntPtr data, Int32 size)
{
if (_FileStream == null) return;
Byte[] buf = new Byte[size];
Marshal.Copy(data, buf, 0, size);
//dont await here - just continue
_FileStream.WriteAsync(buf, 0, size);
}
Run Code Online (Sandbox Code Playgroud)
到目前为止它似乎没有问题.我只想确认如果在上一次迭代完成之前调用此方法会发生什么.
你会注意到我没有等待WriteAsync()电话.我不确定这是否正确,但我使用的API声明在此方法中将操作保持在最低限度,以便不在API内部阻止回调.这似乎是要纠正的事情,只需将数据传递给流,然后立即返回.
有人可以确认如果最后一个WriteAsync()电话还没完成会发生什么,我WriteAsync()再打电话?或者我应该进行awaitWriteAsync()调用?
编辑:我还没有使用上述方法遇到异常,所以我想我的最后一个问题是在外部DLL回调中使用WriteAsync()时是否有任何影响?DLL是第三方Directshow组件.我无法验证它是如何在内部工作的,但它只是通过回调向我提供数据,我将其保存到文件流中.
异步重叠WriteAsync操作没有任何问题,只要它们写入文件的不同,非重叠段:
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var tempFile = System.IO.Path.GetTempFileName();
Console.WriteLine(tempFile);
var fs = new System.IO.FileStream(
tempFile,
System.IO.FileMode.Create,
System.IO.FileAccess.ReadWrite,
System.IO.FileShare.ReadWrite,
bufferSize: 256,
useAsync: true);
fs.SetLength(8192);
var buff1 = Enumerable.Repeat((byte)0, 2048).ToArray();
var buff2 = Enumerable.Repeat((byte)0xFF, 2048).ToArray();
try
{
fs.Seek(0, System.IO.SeekOrigin.Begin);
var task1 = fs.WriteAsync(buff1, 0, buff1.Length);
fs.Seek(buff1.Length, System.IO.SeekOrigin.Begin);
var task2 = fs.WriteAsync(buff2, 0, buff2.Length);
Task.WhenAll(task1, task2).Wait();
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在低级别,它都归结为WriteFile具有非null的API LPOVERLAPPED lpOverlapped,这是Windows API中支持的方案.
如果写入重叠,您仍然不会看到错误,但写入将会竞争,最终结果可能无法预测.
FileStream不是线程安全的。从不同线程写入同一文件的两次写入将无法正常工作。
正如 @Noseratio 所指出的,WriteAsync从同一线程进行重叠调用是可以的。
因此,如果您从不同的线程写入文件,则需要同步对文件的访问。
顺便说一句,我也会修改您的SaveToFile返回任务,并且因为您没有使用await该方法,所以也不需要这样做async。
private Task SaveToFile(IntPtr data, Int32 size)
{
if (_FileStream == null) return;
Byte[] buf = new Byte[size];
Marshal.Copy(data, buf, 0, size);
//dont await here - just continue
return _FileStream.WriteAsync(buf, 0, size);
}
Run Code Online (Sandbox Code Playgroud)