2016-11-30 7 views
0

У меня есть следующий делегат события, который в основном принимает массив байтов и присоединяет его к файловому потоку. Как только он написал 1000 раз, что отслеживается локальной переменной counter, я хочу закрыть текущий поток и открыть новый.Как можно гарантировать, что FileStream будет удален после того, как все WriteAsync() в текущем файле будут завершены?

Я прочитал документацию FileStream и предложил использовать FileStream.WriteAsync() для лучшей производительности.

public void WriteData(byte[] data) 
{ 
    counter++; 
    if (counter == 1000) 
    { 
     counter = 0; 

     // Close the current filestream and open a new one. 
      filestream.Dispose(); 
      filestream = new FileStream(this.outputPath, FileMode.Create, 
      FileAccess.Write, FileShare.None, 4096, true); 
    } 

    filestream.WriteAsync(data, 0, data.Length); 
} 

Однако в приведенной выше функции, моя гипотеза состоит в том, что это может быть так, что все WriteAsync() вызовы не завершены, прежде чем я называю filestream.Dispose(). Есть ли способ гарантировать, что я только Dispose() после того, как все мои звонки WriteAsync() завершены? Обратите внимание, что делегат этого события вызывается последовательно 1000 - 2000 раз в секунду, а WriteAsync копирует 240 КБ на звонок на SSD.

Одно решение, которое я могу думать вместо того, чтобы немедленно утилизации каждого Filestream сразу, я могу хранить его в массив Filestream, а затем избавиться от них, как только я закончил весь процесс записи данных и нет больше событий нет обжиг. Будет ли это работать? Даже тогда, как я могу «дождаться» до тех пор, пока все вызовы WriteAsync() не будут завершены?

+1

'ждут filestream.WriteAsync (...); filestream.Dispose; '? – Kritner

+0

@Kritner Поток не размещается после каждой записи. – Servy

+0

У вас не должно быть асинхронного метода «void». Вы всегда должны выставлять вызывающему устройству средство определения того, когда асинхронное действие завершено (в этом случае, вернув «Задачу»). Обратите внимание, что с вашим текущим кодом вы можете не только избавиться от потока во время записи, но вы можете отправить дополнительную запись, пока более ранняя запись еще не закончена, что также * вызовет проблемы. – Servy

ответ

0

Пока не ответ на точный вопрос, на основе наблюдения в комментариях, я хотел бы предложить вам сделать следующее:

  • Создать ConcurrentQueue в любом увольняет события
  • На каждом событие, добавить в эту очередь
  • Создайте отдельный поток, который обслуживает очередь, удаляет события и записывает их на диск. Затем вы можете точно определить, как часто вы хотите открывать, писать, переименовывать и т. Д., И у вас нет проблем параллелизма потоков в активности файлов, с которыми приходится иметь дело.
  • В зависимости от вашего требования, в потоке писателя вы можете просто опросить очередь каждую секунду или около того, или у вас может быть более сложный подход, используя WaitHandle s, чтобы сигнализировать, когда данные готовы к записи, когда очередь пуста, когда у него есть N элементов и т. д. Поскольку вы так часто накапливаете данные, возможно, опрос прекрасен, так как вы почти всегда найдете данные для записи.
  • Очевидно, что вам необходимо полностью закрыть приложение. прекратите запись из событий, одинарную для записывающего потока, чтобы остановить ее, запустите ее на диск, подождите, пока она остановится.

Это больше работы, но вы получите:

  • гарантируется заказ
  • почти нет времени провели в обработчик событий
  • без проблем параллелизма (для управления установкой и разрыва, за исключением)
  • задержки в письменной форме - напримериз-за ОС, диска, сети - не блокируйте основное приложение
  • риск потери данных о событиях, если вы потеряете питание, или приложение прерывается (у вас будет это с любым решением, которое не дожидается, когда данные будут записаны после каждого события)

Есть, вероятно, готовые решения для этого (использование запоминающего устройства log4net Appender приходит на ум); это если вы хотите бросить свои собственные.

Вы можете сделать это с помощью «стандартной» резьбы (т. Е. Thread), или вы можете просто создать свою нить записи как Task.

 Смежные вопросы

  • Нет связанных вопросов^_^