首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >FileOptions.Asynchronous导致FileStream.BeginRead阻塞

FileOptions.Asynchronous导致FileStream.BeginRead阻塞
EN

Stack Overflow用户
提问于 2012-11-09 07:27:14
回答 2查看 4.5K关注 0票数 4

为什么用FileOptions.Asynchronous创建FileStream会导致FileStream.BeginRead阻塞调用线程?

以下是代码片段:

代码语言:javascript
复制
private static Task<int> ReadFileAsync(string filePath)
  {
     var file = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 64 * 1024, FileOptions.Asynchronous);
     FileInfo fi = new FileInfo(filePath);
     byte[] buffer = new byte[fi.Length];
     Task<int> task = Task<int>.Factory.FromAsync(file.BeginRead, file.EndRead, buffer, 0, buffer.Length, null);         
     return task.ContinueWith(t =>
     {
        file.Close();
        Console.WriteLine("Done ReadFileAsync, read " + t.Result + " bytes.");
        return t.Result;
     });
  }

当使用JetBrains dotPeek研究微软FileStream代码时,他们的代码中似乎有一个bug:

代码语言:javascript
复制
      if (!this._isAsync)
    return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
  else
    return (IAsyncResult) this.BeginReadAsync(array, offset, numBytes, userCallback, stateObject);

BeginRead方法实际上似乎通过调度一个任务来执行异步读取,但是BeginReadAsync方法实际上结束了同步读取。因此,他们的方法命名规则是倒退的,调用哪个方法的逻辑是错误的。如果this._isAsync ==为true,则应调用BeginRead。

因此,似乎要让FileStream.BeginRead立即返回(异步调度读取),您实际上必须将cosntructor中的useAsync参数设置为false。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-11-12 03:34:43

这里有一篇知识库文章,列出了所有可能导致您希望异步执行的代码实际上同步运行的方法。

Asynchronous Disk I/O Appears as Synchronous on Windows NT, Windows 2000, and Windows XP

清单上的内容是否适用于你的情况?

你有没有尝试过用.NET 4.5的ReadAsync method实现同样的行为?

我引用了MSDN的话:

在.NET Framework4及更早版本中,您必须使用BeginRead和EndRead等方法来实现异步I/O操作。这些方法在.NET Framework4.5中仍然可用来支持遗留代码;但是,ReadAsync、WriteAsync、CopyToAsync和FlushAsync等新的异步方法可以帮助您更轻松地实现异步I/O操作。

编辑我正在使用ICH10和Windows7在OCZ Vertex 2上重现256MB文件的问题。我必须生成该文件,重新启动PC以清除文件缓存,然后尝试读取相同的文件。

代码语言:javascript
复制
using System;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication4
{
   class Program
   {
      static void Main(string[] args)
      {
         string fileName = @"C:\Temp\a1.txt";
         int arraySize = 512 * 1024 * 1024;
         var bytes = new byte[arraySize];
         new Random().NextBytes(bytes);

          // This prints false, as expected for async call
         var callback = new AsyncCallback(result =>
                             Console.WriteLine("Completed Synchronously: " + result.CompletedSynchronously));

         try
         {
            // Use this method to generate file...
            //WriteFileWithRandomBytes(fileName, arraySize, bytes, callback);

            Console.WriteLine("ReadFileAsync invoked at " + DateTimeOffset.Now);
            var task = ReadFileAsync(fileName);
            Console.WriteLine("ReadFileAsync completed at " + DateTimeOffset.Now);

            Task.WaitAll(task);
            Console.WriteLine("Wait on a read task completed at " + DateTimeOffset.Now);
         }
         finally
         {
            if (File.Exists(fileName))
               File.Delete(fileName);
         }
      }

      private static void WriteFileWithRandomBytes(string fileName, int arraySize, byte[] bytes, AsyncCallback callback)
      {
         using (var fileStream = new FileStream(fileName,
            FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 128 * 1024, FileOptions.Asynchronous))
         {
            Console.WriteLine("BeginWrite invoked at " + DateTimeOffset.Now);
            var asyncResult = fileStream.BeginWrite(bytes, 0, arraySize, callback, null);


            Console.WriteLine("BeginWrite completed at " + DateTimeOffset.Now);
            // completes in 6 seconds or so...  Expecting instantaneous return instead of blocking

            // I expect runtime to block here...
            Task.WaitAll(Task.Factory.FromAsync(asyncResult, fileStream.EndWrite));

            // or at least when flushing the stream on the following end-curly
         }
      }


      private static Task<int> ReadFileAsync(string filePath)
      {
         FileInfo fi = new FileInfo(filePath);
         byte[] buffer = new byte[fi.Length];

         var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 64 * 1024, FileOptions.Asynchronous);
         Task<int> task = Task<int>.Factory.FromAsync(file.BeginRead, file.EndRead, buffer, 0, buffer.Length, null);
         return task.ContinueWith(t =>
         {
            file.Close();
            Console.WriteLine("Done ReadFileAsync, read " + t.Result + " bytes.");
            return t.Result;
         });
      }
   }
}

当所有其他方法都失败时,here's the reference to unmanaged API documentation

票数 4
EN

Stack Overflow用户

发布于 2013-10-22 23:30:14

您是否尝试传入有效的stateObject,而不是null?与http://msdn.microsoft.com/en-us/library/kztecsys(v=vs.100).aspx的代码进行比较

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13299705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档