На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: JoeUser, Qraizer
  
> Помогите подобрать правильный шаблон проектирования,, который позволяет порождать много инстансов одного класса.
Всем привет.
Есть вот такой набросок псевдокода:
ExpandedWrap disabled
    class IModuleUpgrader
    {
       virtual void SetUpgradeCode() = 0;
       virtual void SetVersion() = 0;
       virtual void UpgradeModule(string modulename) = 0;
    }
     
    struct IsmUpdater : public IModuleUpgrader
    {
      void UpgradeModule(string modulename) override
      {
          parser.ProcessUpgrade();
          parser.Save();
      }
      void SetUpgradeCode() override {}
      void SetVersion() override {}
    private:
      XMLParser parser;
    };
     
    struct WixUpdater : public IModuleUpgrader
    {
      void UpgradeModule(string modulename) override
      {
          parser.ProcessUpgrade();
          parser.Save();
      }
      void SetUpgradeCode() override {}
      void SetVersion() override {}
    private:
      XMLParser parser;
    };
     
    ...
     
    struct UpgradeTool
    {
        void AddUpgradeTool(const std::wstring& ext, std::unique_ptr<IModuleUpgrader>&& upgrader)
        {
           m_scaner.AddFilter(ext);
           m_upgraders.insert(make_pair(ext,std::move(upgrader)));
        }
        
        //! Producer выполняется в отдельном потоке
        void Scann()
        {
            m_scanner.ScannAndPutResultToContainer(m_container);
        }
        
        //! Consummer может выполнятся в отдельных разных потоках
        void Upgrade()
        {
           while(true)
           {
              auto module = m_container.pop();
              auto ext = GetModuleType(module);
              if(m_upgraders.has(ext))
              {
                 auto upgrader = m_upgraders[ext];
                 upgrader->SetUpgradeCode(...);
                 upgrader->SetVersion(...);
                 upgrader->Upgrade();
              }
           }
        }
        private:
            FileScanner m_scanner;
            ThreadSafeQueue<std::wstring> m_container;
            std::map<std::wstring, std::unique_ptr<IModuleUpgrader>> m_upgraders;
    }

По задумке мы пихаем расширения нужных нам файлов в класс UpgradeTool, и класс, который может их обрабатывать.
Дальше запускается отдельный поток, в котором ищутся все файлы с заданным расширением и файлы эти кладутся в отдельную потокобезопасную очередь, потом запускается несколько отдельных потоков, и каждый отдельный поток начинает обрабатывать свой файл.
Но тут есть косяк: Если я вызову AddUpgradeTool(".ext", new IsmUpdater );
То у меня будет 1 объект класса IsmUpdater, а мне нужно чтоб было столько, сколько потоков, но я не могу понять как это сделать.
Вот например приходила такая идея:
ExpandedWrap disabled
        template<typename _Type = IModuleUpgrader>
        struct ProxyModuleUpgrader
        {
            using TModuleUpgrader = _Type;
        };
        std::map<std::wstring, std::unique_ptr<ProxyModuleUpgrader<>>> m_upgraders;
    //! Где то :
            upgrade.AddUpgradeTool<IsmUpdater>(L".ext", new IsmUpdater)
     
    //! Внутри апгрейда
         void UpgradeTool::Upgrade()
        {
           while(true)
           {
                  auto module = m_container.pop();
              auto ext = GetModuleType(module);
              if(m_upgraders.has(ext))
              {
                   auto upgrader = m_upgraders[ext]::TModuleUpgrader;
                 upgrader->SetUpgradeCode(...);
                 upgrader->SetVersion(...);
                 upgrader->Upgrade();
              }
           }
        }

Но эта идея тоже провалилась.
Может быть есть какой то шаблон или прием для решения такой задачи? Я что то не могу сообразить как же так лучше сделать то :unsure:
Цитата Wound @
как же так лучше сделать то

А задача-то какая? Многопоточная обработка файлов по расширениям и/или по группам расширений?
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Многопоточная обработка файлов по расширениям и/или по группам расширений?

В одном потоке запускается хрень(FileScanner), которая ищет все файлы в директории и поддиректориях по указанным расширениям, и пихается путь к найденному файлу в очередь, а потом запускаются несколько потоков, которые должны эту самую очередь выгребать и обновлять каждый файл, в зависимости от типа файла. Один файл может обновлятся достаточно долгое время(от секунды до минуты например).
Для каждого потока должен создаваться отдельный объект класса, который умеет работать с файлом данного типа.
Т.е. один класс на несколько потоков - не варик вообще.
Сообщение отредактировано: Wound -
Цитата Wound @
Вот например приходила такая идея:

    template<typename _Type = IModuleUpgrader>
    struct ProxyModuleUpgrader
    {
        using TModuleUpgrader = _Type;
    };
    std::map<std::wstring, std::unique_ptr<ProxyModuleUpgrader<>>> m_upgraders;
//! Где то :
        upgrade.AddUpgradeTool<IsmUpdater>(L".ext", new IsmUpdater)
 


Можно сделать например так
ExpandedWrap disabled
    std::map<std::wstring, std::function<std::unique_ptr<IModuleUpgrader>()>> upgraders;
    .....
    upgraders.emplace(L".ext", []{return std::make_unique<IsmUpdater>()});
    upgraders.emplace(L".ext2", []{return std::make_unique<WixUpdater>()});
    ....
     
    auto it = upgraders.find(ext);
    if (it == upgraders.end())
      return;
     
    auto upgrader = it->second();
Да примерно так и сделал, только добавил в интерфейс IModuleUpgrader новый чистовиртуальный метод -> virtual std::unique_ptr<IModuleUpgrader> CreateNewInstance() const = 0;
А уж потомки реализуют его как у тебя в лямбде.
Хотя может твой способ и лучше, не нужно писать лишнего метода в интерфейсе.
Спасибо.

Добавлено
Вопрос решен.
Цитата Wound @
Да примерно так и сделал, только добавил в интерфейс IModuleUpgrader новый чистовиртуальный метод -> virtual std::unique_ptr<IModuleUpgrader> CreateNewInstance() const = 0;
А уж потомки реализуют его как у тебя в лямбде.


Его точно не реализуют. Чтобы вызвать виртуальный метод в интерфейсе, нужно сначала создать экземплляр кдасса который реализует этот интерфейс. Он будет через этот метод копировать себя, и больше ничего не делать, вряд ли ты станешь вызывать у него другие методы. Зачем для этого держать отдельный объект? Достаточно указателя на функцию или std::function.
Цитата Олег М @
Его точно не реализуют. Чтобы вызвать виртуальный метод в интерфейсе, нужно сначала создать экземплляр кдасса который реализует этот интерфейс. Он будет через этот метод копировать себя, и больше ничего не делать, вряд ли ты станешь вызывать у него другие методы. Зачем для этого держать отдельный объект? Достаточно указателя на функцию или std::function.

Фишка в том, что интерфейс там появился для того, чтобы внутри void Upgrade() вызвать соответствующие методы:
ExpandedWrap disabled
    void Upgrade()
        {
           while(true)
           {
              auto module = m_container.pop();
              auto ext = GetModuleType(module);
              if(m_upgraders.has(ext))
              {
                 auto upgrader = m_upgraders[ext]; <------ Вот тут вместо auto должна быть копия объекта IsmUpdater или WixUpdater или еще чего то.
                 upgrader->SetUpgradeCode(...);
                 upgrader->SetVersion(...);
                 upgrader->Upgrade();
              }
           }
        }

Для этого я создал интерфейс, и добавил функцию регистрации:
ExpandedWrap disabled
        void UpgradeTool::AddUpgradeTool(std::wstring ext, std::unique_ptr<Msi::IModuleUpgrader>&& upgrader)
        {
            m_scanner.AddExtension(ext);
            m_upgraders.insert(std::make_pair(std::move(ext), std::move(upgrader)));
        }

Теперь в классах IsmUpdater и WixUpdater реализовал чистовиртуальную функцию интерфейса IModuleUpgrader:
ExpandedWrap disabled
        std::unique_ptr<IModuleUpgrader> ISMFileUpdater::CreateNewInstance() const
        {
            std::cout << "ISMFileUpdater" << std::endl;
            return std::make_unique<ISMFileUpdater>();
        }

Теперь в функцию потока void Upgrade() я могу написать так:
ExpandedWrap disabled
    void Upgrade()
        {
           while(true)
           {
              auto module = m_container.pop();
              auto ext = GetModuleType(module);
              if(m_upgraders.has(ext))
              {
                 //auto upgrader = m_upgraders[ext]; <------ Вот тут вместо auto должна быть копия объекта IsmUpdater или WixUpdater или еще чего то.
             std::unique_ptr<Msi::IModuleUpgrader> ptr = m_upgraders[ext];
             auto upgrader = ptr->CreateNewInstance();  
             upgrader->LoadModule(L"test.ism");
                 upgrader->SetUpgradeCode(...);
                 upgrader->SetVersion(...);
                 upgrader->Upgrade();
              }
           }
        }

А регистрировать свои классы вот так:
ExpandedWrap disabled
        UpgradeTool tool;
        tool.AddUpgradeTool(L".ism", std::make_unique<Msi::ISMFileUpdater>());


Это так сейчас сделано, если делать как ты написал с указателем на функцию, то ведь придется в функцию регистрации передавать лямбда выражение целое?
Что то типа:
ExpandedWrap disabled
        UpgradeTool tool;
        tool.AddUpgradeTool(L".ism", []{return std::make_unique<IsmUpdater>()});


Добавлено
Ну в принципе я так и переписал. Просто меня смущает что нужно передавать лямбду в параметр функции. Слишком запутанно выходит. Хотя может и нет.
Сообщение отредактировано: Wound -
Wound, честно говоря, я бы начал немного раньше планировать разработку. А именно с анализа предметной области. Хотя бы с одного вопроса "какие ресурсы компа в потенциале в процессе обработки будут более востребованы?". Если ответ "а хрен его спрогнозирует" - тогда выбираем "классику". А именно, число потоков-обработчиков = N+1, где N-количество ядер проца. А вот, к примеру, если дисковых операций тьма, а математика не только лишь все имена файлов обрабатывает, мало какие данные в файлах обрабатываются (L) :lol: Тут свое построение нужно делать.

Одно понятно, сущностей четыре:

  • Обработчик списка файлов
  • Хранитель стека необработанных файлов (а весьма возможно или вектора, или ваще мапы!)
  • Пулл обработчиков
  • Очередь обработки

Две очевидных стратегии:

  • Наванговали, создали заранее пул обработчиков с нехилым запасом, создали фиксированную очередь обработки, определили строгую стратегию выборки на обработку
  • Решили, пусть прога сама считает что и как создавать на основе статистики уже обработанного. Тут уже придется не полениться. Поискать критерии (расширение, длина файла, дата создания) и корреляция этой хрени с другими параметрами - общем времени обработки, обработки файлов определенного расширения, средними значениями обработки по расширениям (длинам, датам)

Ну и конечно же основной вопрос - если прога одноразовая, используем стратегию намба уан и не паримся ни разу.
Все выше - мое ИМХО.

В качестве бонуса - архивчик, в котором есть полезные книжки по твоему топику, может быть поможет :) :

  • Параллельное и распределенное программирование на C++.Хьюз.djvu
  • Параллельное программирование на С++ в действии.Уильямс.djvu
  • Приемы объектно-ориентированного проектирования. Паттерны проектирования, 2001.Гамма.djvu
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Wound, честно говоря, я бы начал немного раньше планировать разработку. А именно с анализа предметной области. Хотя бы с одного вопроса "какие ресурсы компа в потенциале в процессе обработки будут более востребованы?". Если ответ "а хрен его спрогнозирует" - тогда выбираем "классику". А именно, число потоков-обработчиков = N+1, где N-количество ядер проца. А вот, к примеру, если дисковых операций тьма, а математика не только лишь все имена файлов обрабатывает, мало какие данные в файлах обрабатываются (L) Тут свое построение нужно делать.

Да ресурсов не много нужно. Есть куча инсталяционных файлов Installshield и Wix(*.ism, *.wix), они представляют из себя XML, в них хранится вся информация, из которой потом компилируются инсталяционные пакеты Setup.exe/*.cab.
Инсталяционных файлов много, ну штук под 30 примерно, и есть куча разных версий, которым никто не настраивал Major upgrade, А чтоб Major Upgrade работал, нужно в каждом файле сгенерировать новый ProductCode, потом нужно задать ProductVersion, И прописать все это в таблицу Upgrade - выставить нужные версии. Руками все это делать муторно и долго, и я задолбался. В итоге решил автоматизировать все это дело. Чтобы прога сама искала все нужные файлы и сама апгрейдила все что нужно во время компиляции, тогда даже когда сделают новую ветку, мне не нужно будет там настраивать Major Upgrade.
В итоге я написал XML парсер, который загружает только нужные для апгрейда части, чтобы жрало поменьше памяти, написал класс который апгрейдид все это, и хочу теперь воссоединить это в одно. Так как файлов много, решил что каждый файл будет апгрейдится в отдельном потоке. Сколько для этого нужно потоков пока не знаю, но думаю юзать фьючерсы, там вроде они умные и сами умеют распределять ресуосы системы. Так что конкретно число потоков мне пока не важна. У меня проблема была в том, чтобы в отдельном потоке была отдельная копия класса-апгрейдера. Но вроде уже решилась.
Wound, Киля, самый главный вопрос - задача разовая или перманентная по времени?

Добавлено
Цитата Wound @
фьючерсы, там вроде они умные и сами умеют распределять ресуосы системы

Это заблуждение! Распределять ресурсы умеет ОС. Программер может помочь, зная специфику обработки.
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Wound, Киля, самый главный вопрос - задача разовая или перманентная по времени?

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


Цитата JoeUser @
Это заблуждение! Распределять ресурсы умеет ОС. Программер может помочь, зная специфику обработки.

Ну у Мейерса как раз и написано чтобы отдавали предпочтение фьючерсам, так как они шибко умные и сами знают нужно ли порождать поток или исполнять в текущем, а так же все тонкости балансировщика они тоже знают.
Цитата Wound @
Цитата JoeUser @
Wound, Киля, самый главный вопрос - задача разовая или перманентная по времени?

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

Тогда, действительно, задача интересна и стоит усилий!

Цитата Wound @
Цитата JoeUser @
Это заблуждение! Распределять ресурсы умеет ОС. Программер может помочь, зная специфику обработки.
Ну у Мейерса как раз и написано чтобы отдавали предпочтение фьючерсам, так как они шибко умные и сами знают нужно ли порождать поток или исполнять в текущем, а так же все тонкости балансировщика они тоже знают.

Философское отступление. Несколько лет назад у меня спала "пелена из глаз". До этого, в течении многого времени, я считал себя заядлым агностиком. Многие вааще не понимали о чем речь. Но пришло осознание - я не агностик или атеист, я - неверующий. Даже религия тут не при чем! Я не верю ваще, ни во что. Полностью. Я пытаюсь воспроизвести и оценить. Гадил я с Пизанской башни на аксиомы "аксакалов". Но ... приду и проверю :lol:

... это я кидаю камень в сторону Меерса :lol:

Есть "логика", есть высказывания Меерса, есть куча методик шкальных оценок достоверности. Ну и есть чуйка))) Поверил во "фьючерсы" - это не смертельно! Возьми вычлени репрезентативную выборку результатов синтетических тестов на своих данных - и ты поймешь. Нужно ли слепо идти за Мейерсом, или эффективнее просто прислушиваться, приглядоваться, записывать ходы... E2-E4?
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Есть "логика", есть высказывания Меерса, есть куча методик шкальных оценок достоверности. Ну и есть чуйка))) Поверил во "фьючерсы" - это не смертельно! Возьми вычлени репрезентативную выборку результатов синтетических тестов на своих данных - и ты поймешь. Нужно ли слепо идти за Мейерсом, или эффективнее просто прислушиваться, приглядоваться, записывать ходы... E2-E4?

Дело в том, что фьючерсы дают чуть больше функционала, чем потоки. Например, если внутри потока сгенерируется исключение, то ты его просто не словишь, с фьючерсами - легко обработать этот вариант, так же можно получить возвращаемое потоком значение.
Ну и вывод, взято у Майерса:
Цитата
Следует запомнить

API std::thrеаd не предлагает способа непосредственного получения
возвращаемых значений из асинхронно выполняемых функций, и, если такие
функции генерируют исключения, программа завершается.

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

Вообще у него вроде понятно расписано, чтобы знать что как работает, а не верить :-?
Сообщение отредактировано: Wound -
Цитата Wound @
Вообще у него вроде понятно расписано, чтобы знать что как работает, а не верить :-?

Вот и я говорю - написано одно, а так ли это на самом деле? Я понимаю, когда в реализацию компилятора/линкера вводят особенности архитектуры. Но вот на автомате предусмотреть особенности конкретной модели проца - это совсем другое.
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
Вот и я говорю - написано одно, а так ли это на самом деле? Я понимаю, когда в реализацию компилятора/линкера вводят особенности архитектуры. Но вот на автомате предусмотреть особенности конкретной модели проца - это совсем другое.

При прочих равных фьючерсы более предпочитетельнее, чем потоки. А пилить какие то узкие места в многопоточности под конкретные модели процессора у меня задачи не стоит.
Цитата JoeUser @
Вот и я говорю - написано одно, а так ли это на самом деле?

И конечно же сам Мейерс этим вопросом не задавался :crazy:
Подпись была включена в связи с окончанием срока наказания
Цитата OpenGL @
И конечно же сам Мейерс этим вопросом не задавался

А тут задавайся, не задавайся, а на уровне только языка всех возможностей аппаратуры и операционной системы - не поднять.
Мейерс же рассуждает как реализовать ту или иную фичу в рамках Стандарта С++.
Мои программные ништякиhttp://majestio.info
Цитата Wound @
В одном потоке запускается хрень(FileScanner), которая ищет все файлы в директории и поддиректориях по указанным расширениям, и пихается путь к найденному файлу в очередь, а потом запускаются несколько потоков, которые должны эту самую очередь выгребать и обновлять каждый файл, в зависимости от типа файла.

Потенциально опасная и неприятная ситуация.
На первый взгляд она не заметна, но она есть.
---
В такой архитектуре заложен вероятностный исход с точки зрения
производительности. А именно:
1. Предположим, 1-й поток начал обрабатывать первый файл.
Головки жёсткого диска поехали в направлении расположения файла 1 на диске.
2. Прошёл системный квант времени. 1-й файл был достигнут, началась работа
но она не была закончена.
3. 2-й поток получил время для обработки 2-го файла.
Головки жёсткого диска поехали в направлении расположения файла 2 на диске.
И вот тут, по не счастливому стечению обстоятельств, файл оказался
"очень далеко" с точки зрения позиционировании головок. А также
с точки зрения фрагментаци 2-го файла.
4. За предоставленный квант времени 2-й поток не успел обработать
2-й файл и головки поехали в направлении 1-го файла.
---
В результате огромное время будет тратиться на электро-механические операции
и производительность может сильно снизиться. Особенно, если добавить ещё
n потоков и n обрабатываемых файлов.
Подпись была выключена в связи с наложенным заземлением.
Цитата ЫукпШ @
В такой архитектуре заложен вероятностный исход с точки зрения
производительности. А именно:

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

Добавлено
Ну и вроде как std::async может решить эту задачу. Так как у библиотеки есть вся картина происходящего.
Сообщение отредактировано: Wound -
Цитата Wound @
А как в винде все это работает? :huh:

ЫукпШ не учитывает небольшого нюанса - различные ухищрения как в плане аппаратной оптимизации работы отдельного HDD, так и при объединении носителей в массивы. Чтение-запись работают не так примитивно.

И, тем не менее, ЫукпШ кагбэ намекает: "Киля, выдели в своей проге отдельный поток 'читатель-писатель' на каждый отдельный носитель. И загружай его заданиями от потоков 'считателей'. Ибо носитель не может выполнять несколько операций одновременно" :lol:

Чисто ИМХО :popcorn:
Мои программные ништякиhttp://majestio.info
Цитата Wound @
А как в винде все это работает? :huh:

А наудачу. Принципиально никак не лечится.
Это потенциальная проблема для любой много-потоковой системы.
Всё проявится наиболее сильно в слабых, низко-производительных случаях.
Скрытый текст

Однажды я такое видел - неудачно запущенный набор программ работал 3 часа.
На системном уровне лечится просто применением всё более совершенных аппаратных средств.
Твердотельные диски - это шаг вперёд.

Формально, конечно, ты прав. Система предоставляет нам набор услуг, мы ими пользуемся.
Как она решает проблемы внутри не наше дело.
Но всё-так лучше учитывать несовершенство аппаратных и программных средств.
Если есть уязвимое место, зачем непременно туда колоть острым ?
Например - поручи работать с файлами одному потоку и всё.
Где и как ты получаешь выгоду от много-потоковой обработки файлов ?
Обязателен ли этот вариант или можно обойтись одним потоком ?

Добавлено
Цитата JoeUser @
Чтение-запись работают не так примитивно.

Когда-то я тоже так думал.
Что-то не так у Виндус с кэшем.
Вот только недавно чистил старые коды для Виндус - раньше я думал, "что там кэш есть" и всё такое..
Понадеялся, так сказать.
Не знаю, что там имеется, но после встраивания "кэша" в тело программы (как это я обычно делал в DOS)
скорость работы увеличилась на 2 порядка (в сто раз).
Сообщение отредактировано: ЫукпШ -
Подпись была выключена в связи с наложенным заземлением.
С управлением памятью у винды беда. Часто замечал, что винда для ускорения обмена с диском отдаёт почти всю память под кеш, для чего выгружает часть программ в своп, в результате интенсивность обращений к диску увеличивается и она дополнительно освобождает память под кеш, выгружая программы в своп, и так, пока система колом не встанет, поскольку у всех активных программ ошибки страниц так и бегут. При том, что сами программы к диску не обращаются, и памяти занимают много меньше наличной физической.

Добавлено
И, похоже, не лучше обстоит дело с приоритетами задач.

Однажды так случилось, что на рабочей станции по удалёнке запустили две копии приложения. Обеим копиям требовалось под 90% наличной памяти, причём они бегали по всей памяти довольно случайно. Я решил притормозить свою копию, чтобы вторая выполнилась, пока я на работе, а потом моя работала. Залез в диспетчер задач и поставил своей низший приоритет (Idle-режим). И вдруг обнаружил, что моя задача стала утилизировать около 80% процессорного времени (это имея пониженный приоритет-то). Пришлось её вообще приостановить. Постепенно моя задача вытеснилась в своп, та задача быстро просчиталас и завершиласьь. Я свою возобновил и пошёл домой. В результате обе задачи утром оказались просчитаны. А так боюсь пришлось бы до обеда ждать, и то не факт, что завершились бы.
Всё написанное выше это всего лишь моё мнение, возможно ошибочное.
amk, это все "кофейная гуща".
Основной вопрос, надеюсь, без возражений? ... "Как загрузить по максимуму самое медленное устройство?" Ога???
SergI, все расписал правильно, имхо.
Мои программные ништякиhttp://majestio.info
Цитата JoeUser @
"Как загрузить по максимуму самое медленное устройство?" Ога???
Как, как? Открыть одновременно несколько десятков файлов и дёргать из них в случайном порядке по нескольку байт. Час-другой глядишь, оно и рассыпется. Или хотя бы сервоусилители привода головок сгорят к чертям.
Всё написанное выше это всего лишь моё мнение, возможно ошибочное.
Скрытый текст
amk, злой ты! Не любишь механику :scratch:
Мои программные ништякиhttp://majestio.info
JoeUser, я стараюсь больше одного файла за раз не открывать. Винда и без меня постарается диск убить досрочно.
Всё написанное выше это всего лишь моё мнение, возможно ошибочное.
Цитата amk @
JoeUser, я стараюсь больше одного файла за раз не открывать.

Ну "открыть" - это еще не значит выполнить I/O.
А вот многопоточная работа с файлами - тут действительно вопросы.
Мои программные ништякиhttp://majestio.info
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,2436 ]   [ 23 queries used ]   [ Generated: 21.07.18, 17:38 GMT ]