【问题标题】:Calling a void async. - Event based pattern, or another method?调用 void 异步。 - 基于事件的模式,还是其他方法?
【发布时间】:2010-03-24 03:48:49
【问题描述】:

我有一个基本上将文件存储在 amazon s3 中的类。 这是它的样子(简化)

public class S3FileStore
{
   public void PutFile(string ID, Stream content)
      {
          //do stuff
      }
}

在我的客户端应用程序中,我希望能够调用:

var s3 = new() S3FileStore();
s3.PutFile ("myId", File.OpenRead(@"C:\myFile1"));
s3.PutFile ("myId", File.OpenRead(@"C:\myFile2"));
s3.PutFile ("myId", File.OpenRead(@"C:\myFile3"));

我希望这是一个异步操作 - 我希望 S3FileStore 来处理这个(我不希望我的调用者必须异步执行 PutFile)但是,我希望能够捕获异常/判断是否为每个文件完成的操作。

我看过基于事件的异步调用,尤其是这个: http://blogs.windowsclient.net/rendle/archive/2008/11/04/functional-shortcuts-2-event-based-asynchronous-pattern.aspx

但是,我看不到如何调用我的 PutFile (void) 方法?

还有更好的例子吗?

【问题讨论】:

    标签: c# asynchronous


    【解决方案1】:

    查看这个问题的解决方案:Adding cancel ability and exception handling to async code。希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      BackgroundWorker 基类可能值得一看,还有线程池:

      ThreadPool.QueueUserWorkItem(delegate 
          { 
             s3.PutFile ("myId", File.OpenRead(@"C:\myFile1"));
          });
      

      这基本上就是您对 Action/BeginInvoke 模式所做的事情。使用 BeginInvoke,您还会收到一个 IAsyncResult,您可以在其上调用 .WaitOne() 以阻塞当前线程,直到操作完成,以备不时之需。您将为每个要保存的文件触发一个新的BeginInvoke

      如果您需要经常这样做,更复杂的版本可能是将队列与 BackgroundWorker 结合使用,例如:

      public sealed class S3StoreLikePutFileWorker<TYourData> : BackgroundWorker
      {
          private AutoResetEvent WakeUpEvent = new AutoResetEvent(false);
      
          private Queue<TYourData> DataQueue = new Queue<TYourData>();
      
          private volatile bool StopWork = false;
      
          public void PutFile(TYourData dataToWrite)
          {
              DataQueue.Enqueue(dataToWrite);
              WakeUpEvent.Set();
          }
      
          public void Close()
          {
              StopWork = true;
              WakeUpEvent.Set();
          }
      
          private override void OnDoWork(DoWorkEventArgs e)
          {
              do
              {
                  // sleep until there is something to do
                  WakeUpEvent.WaitOne();
                  if(StopWork) break;
      
                  // Write data, if available
                  while(DataQueue.Count > 0)
                  {
                      TYourData yourDataToWrite = DataQueue.Dequeue();
                      // write data to file
                  }
              }
              while(!StopWork);
          }
      }
      

      取决于您需要的复杂程度。

      BackgroundWorker 支持进度反馈(在构造函数中设置WorkerReportsProgress = true;),如果需要,您还可以添加自定义事件来报告错误:

      // create a custom EventArgs class that provides the information you need
      public sealed class MyEventArgs : EventArgs {
         // Add information about the file
      }
      
      // ... define the event in the worker class ...
      public event EventHandler<MyEventArgs> ErrorOccured;
      
      // ... call it in the worker class (if needed) ...
      if(ErrorOccured != null) ErrorOccured(this, new MyEventArgs(/*...*/));
      
      

      【讨论】:

        猜你喜欢
        • 2018-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-13
        • 2021-10-20
        • 1970-01-01
        相关资源
        最近更新 更多