Вызов асинхронной пустоты. - Шаблон на основе событий или другой метод? - PullRequest
1 голос
/ 23 марта 2010

У меня есть класс, который в основном хранит файлы в 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)?

Есть ли лучшие примеры?

Ответы [ 2 ]

1 голос
/ 23 марта 2010

Может стоить посмотреть базовый класс 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(/*...*/));

1 голос
/ 23 марта 2010

Посмотрите на решение этого вопроса: Добавление возможности отмены и обработки исключений в асинхронный код . Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...