C# FileStream.ReadAsync有时是否同步完成?

C# FileStream.ReadAsync有时是否同步完成?,c#,asynchronous,task-parallel-library,C#,Asynchronous,Task Parallel Library,试试这个。使用单个按钮和按钮单击事件的以下代码设置新的Windows窗体应用程序: private async void button1_Click(object sender, EventArgs e) { using (var file = File.OpenRead(@"C:\Temp\Sample.txt")) { byte[] buffer = new byte[4096]; int threadId = Thread.CurrentTh

试试这个。使用单个按钮和按钮单击事件的以下代码设置新的Windows窗体应用程序:

private async void button1_Click(object sender, EventArgs e)
{
    using (var file = File.OpenRead(@"C:\Temp\Sample.txt"))
    {
        byte[] buffer = new byte[4096];
        int threadId = Thread.CurrentThread.ManagedThreadId;
        int read = await file.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
        Debug.Assert(threadId != Thread.CurrentThread.ManagedThreadId);
    }
}
然后运行应用程序并快速单击按钮。如果您的经验与我的类似,您会发现有时它会按预期工作,但在其他时间,
Debug.Assert
将失败

根据我对
configurewait
的理解,为
continueOnCapturedContext
传递
false
应该指示任务不要同步回“主”上下文(在这种情况下是UI线程),并且应该在线程池上继续执行

那么为什么断言会随机失败呢?我只能假设,
ReadAsync
有时不会在后台线程上完成,即它将同步完成

此行为符合KB 156932-:

大多数I/O驱动程序(磁盘、通信和其他)都有特殊情况 代码,其中,如果可以“立即”完成I/O请求 操作将完成,ReadFile或WriteFile函数 将返回真值。在所有方面,这些类型的操作似乎都是 同步的通常,对于磁盘设备,I/O请求可以是 数据缓存在内存中时“立即”完成

我的假设和测试应用程序正确吗?
ReadAsync
方法有时可以同步完成吗?有没有一种方法可以保证执行总是在后台线程上继续

这个问题对我的应用程序造成了严重破坏,它使用COM对象,要求我知道哪个线程一直在执行


Windows 7 64位.NET 4.5.1

如果文件读取在调用wait之前同步完成,我可以相当肯定的是,异步编译器魔法不会发生,并且会在调用线程上同步继续执行。如果我想保证工作从线程池线程开始,我会使用
Task.Run(()=>file.ReadAsync(buffer,0,buffer.Length))
将工作排队到线程池。

如果对
任务使用
wait
时,如果任务已经完成,代码将同步执行。然后对该任务调用
ConfigureAwait
,将不会有任何区别,因为不会涉及其他线程

听起来好像数据在内存中(因为重复读取同一文件)
file.ReadAsync
可以同步完成,因此它将在同一线程上完成

ReadAsync方法有时可以同步完成吗

对。由于操作系统级别和.NET流类型中的缓冲区,这种情况并不少见

有没有一种方法可以保证执行总是在后台线程上继续

如果总是希望代码在线程池线程上执行,请使用
Task.Run

private async void button1_Click(object sender, EventArgs e)
{
  using (var file = File.OpenRead(@"C:\Temp\Sample.txt"))
  {
    byte[] buffer = new byte[4096];
    int threadId = Thread.CurrentThread.ManagedThreadId;
    int read = await file.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
    await Task.Run(() =>
    {
      Debug.Assert(threadId != Thread.CurrentThread.ManagedThreadId);
    }).ConfigureAwait(false);
  }
}

ConfigureAwait
是一个优化提示,而不是移动到后台线程的命令<如果操作已完成,则代码>配置等待
无效。在这种情况下,
await
遵循一个基本上意味着它是同步继续的,因此任何
ConfigureAwait
提示都会被忽略。

您不以异步模式打开文件有什么原因吗?当使用指定的
FileStream
重载打开文件时,我发现上面描述的行为没有改变“异步模式”。谢谢Stephen。难道只有我一个人在思考
ConfigureAwait
有点误导吗?我在MSDN上没有发现任何东西向我表明这只是一个提示而非事实。例如,您的代码示例使用
ConfigureAwait(false)
任务上。运行
。我有什么保证
任务。运行
文件流更能在预期的上下文中完成。ReadAsync使用相同的方法吗?我的代码在没有
配置等待
调用的情况下工作完全相同;它的效率会稍低一些。这就是为什么取消
任务。运行
,该任务保证在线程池线程上运行,而不是在任何延续上运行。