调用void async。 - 基于事件的模式,还是其他方法?

时间:2010-03-23 16:29:33

标签: c# asynchronous

我有一个基本上在亚马逊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)方法?

有没有更好的例子?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

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

这基本上是你对Action / BeginInvoke模式的处理方式。使用BeginInvoke,您还会收到一个IAsyncResult,您可以在其上调用.WaitOne()来阻止当前线程,直到操作完成,以防您需要。您将为要保存的每个文件触发新的BeginInvoke

如果您需要经常这样做,更复杂的版本可能是将Queue与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(/*...*/));