none
Как использовать ThreadPool для FileStream RRS feed

  • Вопрос

  • System.Threading.ThreadPool.QueueUserWorkItem(_=>MemoryMappedSign());


    Как сделать  с FileStream  также как в верхнем примере?

    FileStream Sys_PlOrder = new FileStream(mP

    athFile, FileMode.Append, FileAccess.Write); _StreamWriterSystems = new StreamWriter(Sys_PlOrder); _StreamWriterSystems.WriteLine(.....); _StreamWriterSystems.Close();

    Приходится часто эту операцию совершать .И еще бывает, что при доступе к одному и тому же файлу из разных частей программы всплывает ошибка: Процесс не может получить доступ к файлу т к он используется другим процессом. Как эту проблему решить?


    Eugene


    26 сентября 2013 г. 12:13

Ответы

  • Что именно вы хотите добиться? Уменьшить количество потребляемой памяти с помощью выполнения в другом потоке вряд ли возможно.

    > Процесс не может получить доступ к файлу т к он используется другим процессом.

    Полагаю, для избежания этого следует использовать перегрузку конструктора с указанием параметра FileShare - это позволит одновременную работу с файлом одновременно разными потребителями.

    Если нужно обеспечить параллельную (асинхронную) работу с файловым потоком, то можно использовать методы BeginRead, BeginWrite - они для этого и предназначены. При этом следует указать при создании стрима параметр FileOptions.Asynchronous.

    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 6:25
    26 сентября 2013 г. 19:18
  • Можно организовать примерно так:
    using System.Collections.Concurrent;
    using System.IO;
    using System.Threading;
    
    private static BlockingCollection<string> OpenFile(string fileName){
        BlockingCollection<string> writeData=new BlockingCollection<string>();
        ThreadPool.QueueUserWorkItem(_=>{
            File.AppendAllLines(fileName,writeData.GetConsumingEnumerable());
            writeData.Dispose();
        });
        return writeData;
    }
    Далее в основной программа, когда нужно записать в файл:
    // Открыть файл
    BlockingCollection<string> file=OpenFile("FileName.txt");
    
    // Записать в файл
    file.Add("some string");
    file.Add("some other string");
    file.Add("some other other string");
    
    // Закрыть файл
    file.CompleteAdding();
    Ну и файл разумнее открыть в начале программы и закрыть в конце, а не отрывать/закрывать ради одной строчки.
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 6:25
    27 сентября 2013 г. 3:37
  • Если Вы не прекращаете использовать файл, то незачем его закрывать. Только лишние расходы на постоянное переоткрытие файла. Размер буфера по умолчанию для FileStream 4096 байт, всё остальное будет в файле. От туда, куда добавляет Add, данные сразу забираются и пишутся в файл, так что накапливаться они будут только, если не будут успевать записываться на диск.
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 11:43
    27 сентября 2013 г. 10:00
  • Лучше выполнять, а то данные из буфера могут так и не скинуться в файл. Можете добавить эту команду например в обработчик закрытия окна или завершения приложения.
    По умолчанию используется кодировка UTF8. Если хотите можете указать любую другую:
    File.AppendAllLines(fileName,writeData.GetConsumingEnumerable(),Encoding.GetEncoding(1251));
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 11:43
    27 сентября 2013 г. 11:12

Все ответы

  • Что именно вы хотите добиться? Уменьшить количество потребляемой памяти с помощью выполнения в другом потоке вряд ли возможно.

    > Процесс не может получить доступ к файлу т к он используется другим процессом.

    Полагаю, для избежания этого следует использовать перегрузку конструктора с указанием параметра FileShare - это позволит одновременную работу с файлом одновременно разными потребителями.

    Если нужно обеспечить параллельную (асинхронную) работу с файловым потоком, то можно использовать методы BeginRead, BeginWrite - они для этого и предназначены. При этом следует указать при создании стрима параметр FileOptions.Asynchronous.

    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 6:25
    26 сентября 2013 г. 19:18
  • Мне в некоторых случаях нужно чтобы запись  файл не тормозила работу программы т е чтобы программа дальше исполнялась,  а поток записи в файл исполнялся без возврата к точке вызова.

    Под асинхронной работой вы это имеете  ввиду?

    Не пойму куда писать FileOptions.Asynchronous?

    C BeginWrite тоже не пойму,  мне нужно  в итоге выполнить  запись строки:

      _StreamWriterSystems.WriteLine(...);

    т е мне нужно строку в файл добавить, а там что-то с байтами связано.

    в MSDN

    http://msdn.microsoft.com/ru-ru/library/system.io.filestream.writeasync.aspx

    рекомендуется использовать:

    WriteAsync(Byte[], Int32, Int32, CancellationToken)

    Пока у меня так выглядит.

    FileStream CollectProfil = new FileStream("D:\\AA.txt", FileMode.Append, FileAccess.Write, FileShare.Write);
    А по pool ничего сказать не можете? А то с memory mapped переход к работе с pool мне сильно помог освободить память. Вот и здесь хочу вместо создания потока сделать реализацию через pool и не знаю как.


    Eugene





    26 сентября 2013 г. 19:57
  • Какую версию .NET Framework используете? Может быть, проще будет использовать выделенный поток, который будет работать с файлом?

    27 сентября 2013 г. 0:28
  • FrameWork 4

    У меня есть процедуры, где путь и имя файла являются параметрами.

    Т к я работаю с он лайн данными и обращений достаточно много, то постоянное создание новых потоков плохо для сборщика мусора.

    Мне так ThreadPool понравился и странно что нет прямого решения для FileStream, вроде частный случай потока.


    Eugene


    27 сентября 2013 г. 2:06
  • Сколько у Вас примерно разных файлов в которые необходимо вести запись? Я так понимаю: у Вас приходит строчка и имя файла, в который её надо записать и Вам надо по мере прихода данных их записывать.
    27 сентября 2013 г. 2:39
  • Т к я работаю с он лайн данными и обращений достаточно много, то постоянное создание новых потоков плохо для сборщика мусора.

    Мне так ThreadPool понравился и странно что нет прямого решения для FileStream, вроде частный случай потока.

    Я так понимаю, вас ввёл в заблуждение термин "поток", которым в русском языке обозначают английские термины Stream и Thread. Дело в том, что стрим - это поток ввода-вывода, используется для приёма-передачи данных. А тред (буквальный перевод - "нить") - это поток выполнения программы. К сожалению, такая путаница имеет место быть.

    Зачастую, чтобы было точно понятно, о каком потоке идёт речь, так и пишут: нить, что означает Thread, и поток, что означает Stream. Или используют кальку с английского - стрим и тред.

    То есть, ThreadPool и Stream никаким образом не связаны.

    27 сентября 2013 г. 2:43
  • Бывает режим сбора информации(теста) включаю и там файлов 20.

    Если решения для этого нет простого, то пусть будет решение для определенного файла. Есть файлы 2-3 которые используются всегда.


    Eugene

    27 сентября 2013 г. 2:43
  • Значит я могу вызов процедуры печати выполнить через ThreadPool и будет быстрее? И может там проще асинхронный вызов организовать? Задача: сделать так, чтобы печать(или проигрывание звукового сигнала) не тормозила исполнение программы т к поток данных бывает насыщенный и лишняя работа в основном Thread не нужна.

    Eugene


    27 сентября 2013 г. 2:55
  • Можно организовать примерно так:
    using System.Collections.Concurrent;
    using System.IO;
    using System.Threading;
    
    private static BlockingCollection<string> OpenFile(string fileName){
        BlockingCollection<string> writeData=new BlockingCollection<string>();
        ThreadPool.QueueUserWorkItem(_=>{
            File.AppendAllLines(fileName,writeData.GetConsumingEnumerable());
            writeData.Dispose();
        });
        return writeData;
    }
    Далее в основной программа, когда нужно записать в файл:
    // Открыть файл
    BlockingCollection<string> file=OpenFile("FileName.txt");
    
    // Записать в файл
    file.Add("some string");
    file.Add("some other string");
    file.Add("some other other string");
    
    // Закрыть файл
    file.CompleteAdding();
    Ну и файл разумнее открыть в начале программы и закрыть в конце, а не отрывать/закрывать ради одной строчки.
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 6:25
    27 сентября 2013 г. 3:37
  • File.AppendAllLines(fileName, writeData.GetConsumingEnumerable());

    Здесь сразу пишет, что процесс не может получить доступ к файлу т к он испоьзуется другим процессом.

    Eugene

    27 сентября 2013 г. 7:10
  • А Вы точно не пытаетесь открыть один и тоже файл дважды? Может быть у Вас запущена вторая копия приложения, которая этот файл уже открыла?
    27 сентября 2013 г. 7:15
  • Печать в файл находится в методе и он вызывается при последовательном прохождении основного  тела программы.

     Я сейчас все переделываю, чтобы открывать файл один раз. Но все же интересно, есть ли защита от повторного открывания файла.

    Выше мне говорили что для FileStream есть параметр FileShare.Write, может и здесь также что-то такое есть. Защита от случайного повторного открытия не помешает.


    Eugene


    27 сентября 2013 г. 7:41
  • Сейчас все сделал, чтобы в теле основного метода работало открытие только один раз.

    Вылетает практически при запуске. Циклов 5-100 проходит без ошибок, но Add внутри нет пока  т к они позже активируются.

    Не может получить доступ к файлу т к он используется другим процессом.Я точки останова поставил, все нормально, до команды

    file.CompleteAdding();

    доходит на каждой итерации.

    До запуска такого файла вообще нет и с ним никто другой работать не может.


    Eugene



    27 сентября 2013 г. 9:09
  • У Вас основной метод в цикле или цикл в основном методе?

    27 сентября 2013 г. 9:17
  • У меня основной метод запускается через обработчик событий. Каждый новый тик с биржи вызывает запуск метода.

    В методе происходит и открытие и закрытие файла.


    Eugene

    27 сентября 2013 г. 9:22
  • Перенесите открытие файла и закрытие файла за пределы основного метода, чтобы файл открывался при запуске мониторинга и закрывался при остановке, а не при каждой итерации.
    27 сентября 2013 г. 9:32
  • У меня програма может и сутки работать. Все равно так сделать? Я в MainWindow могу перенести. А в течении дня в файле данные меняться будут?

    И тогда данные будут накапливаться не только в файле, но и там куда Add добавляет. Зачем?

    Там данных может быть и 20 Mб за сутки.

    И когда я в методе печати все делал, то почему-то такой ошибки не выдавалось, хотя там частота гораздо выше.

    Может все дело в нулевом объеме при добавлении, может поставить ограничитель в метод OpenFiLe на нулевой объем(не знаю как только).

    Раз указывает на строку при ошибке:

     File.AppendAllLines(fileName, writeData.GetConsumingEnumerable());


    Eugene



    27 сентября 2013 г. 9:42
  • Если Вы не прекращаете использовать файл, то незачем его закрывать. Только лишние расходы на постоянное переоткрытие файла. Размер буфера по умолчанию для FileStream 4096 байт, всё остальное будет в файле. От туда, куда добавляет Add, данные сразу забираются и пишутся в файл, так что накапливаться они будут только, если не будут успевать записываться на диск.
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 11:43
    27 сентября 2013 г. 10:00
  • Значит операцию закрытия

    file.CompleteAdding();

    можно вообще не выполнять, а то я в конструкторе файл открыл и куда эту строку ставить не знаю?

    И с кодировкой проблемы в файле.(Кириллица) Как это исправить?

    Странно, при очередном открытии файла все с кодировкой нормально стало.


    Eugene



    27 сентября 2013 г. 10:32
  • Лучше выполнять, а то данные из буфера могут так и не скинуться в файл. Можете добавить эту команду например в обработчик закрытия окна или завершения приложения.
    По умолчанию используется кодировка UTF8. Если хотите можете указать любую другую:
    File.AppendAllLines(fileName,writeData.GetConsumingEnumerable(),Encoding.GetEncoding(1251));
    • Помечено в качестве ответа Евгений771 27 сентября 2013 г. 11:43
    27 сентября 2013 г. 11:12