Неориентированный на многопотоковое исполнение файловый ввод-вывод в C/C++

Я обычно использую этот дополнительный метод с анонимными типами для получения рубина крыла словаря

public static Dictionary<string, object> ToDictionary(this object o)
{
    var dictionary = new Dictionary<string, object>();

    foreach (var propertyInfo in o.GetType().GetProperties())
    {
        if (propertyInfo.GetIndexParameters().Length == 0)
        {
            dictionary.Add(propertyInfo.Name, propertyInfo.GetValue(o, null));
        }
    }

    return dictionary;
}

, можно использовать его

var dummy = new { color = "#000000", width = "100%", id = "myid" };
Dictionary<string, object> dict = dummy.ToDictionary();

, И с расширенным методом как

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (T item in source)
    {
        action(item);
    }
}

можно сделать это

dummy.ToDictionary().ForEach((p) => Console.Write("{0}='{1}' ", p.Key, p.Value));

Вывод

цвет = '#000000' ширина = '100%-й' идентификатор ='myid'

5
задан Josh Kelley 29 July 2009 в 13:47
поделиться

6 ответов

Я бы просто не выполнял ввод-вывод char за раз, если это разумно с точки зрения производительности.

3
ответ дан 14 December 2019 в 04:44
поделиться

Самый простой способ - прочитать весь файл в памяти, а затем предоставить свой собственный интерфейс, подобный fgetc, для этого буфера.

1
ответ дан 14 December 2019 в 04:44
поделиться

Почему бы просто не отобразить файл в памяти? Отображение памяти переносимо (за исключением Windows Vista, которая требует, чтобы вы перескочили через надежды использовать его сейчас, тупицы). Во всяком случае, сопоставьте свой файл с памятью, и есть ли у вас собственная блокировка / не блокировка полученной области памяти.

ОС обрабатывает все блокировки, необходимые для фактического чтения с диска - вы НИКОГДА не сможете устранить эти накладные расходы. Но с другой стороны, на накладные расходы на обработку не повлияет посторонняя блокировка, кроме той, которую вы делаете сами.

1
ответ дан 14 December 2019 в 04:44
поделиться

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

1
ответ дан 14 December 2019 в 04:44
поделиться

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

поток 1 должен писать: abc
поток 2 должен написать: def

Результат может выглядеть так: adebcf вместо abcdef или defabc. Это связано с тем, что часовой реализован для блокировки и разблокировки каждого символа.

Стандарт определяет его для всех функций и операторов, имеющих дело с istream или ostream. Единственный способ избежать этого - использовать буферы потока и собственную блокировку (например, для каждой строки).

Я написал приложение, которое выводит некоторые данные в файл и измеряет скорость. Если вы добавите сюда функцию, которая напрямую использует fstream без использования буфера и очистки, вы увидите разницу в скорости. Он использует ускорение, но я надеюсь, что это не проблема для вас. Попробуйте удалить все стримбуферы и увидеть разницу с ними и без них. В моем случае снижение производительности было в 2-3 раза или около того.

, следующая за статьей Н. Майерс объяснит, как работают локали и часовой в C ++ IOStreams. И обязательно посмотрите в стандартном документе ISO C ++, где функции используют часовую.

Удачи,
Ovanes

#include <vector>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstdlib>

#include <boost/progress.hpp>
#include <boost/shared_ptr.hpp>

double do_copy_via_streambuf()
{
  const size_t len = 1024*2048;
  const size_t factor = 5;
  ::std::vector<char> data(len, 1);

  std::vector<char> buffer(len*factor, 0);

  ::std::ofstream
    ofs("test.dat", ::std::ios_base::binary|::std::ios_base::out);
  noskipws(ofs);

  std::streambuf* rdbuf = ofs.rdbuf()->pubsetbuf(&buffer[0], buffer.size());

  ::std::ostreambuf_iterator<char> oi(rdbuf);

  boost::progress_timer pt;

  for(size_t i=1; i<=250; ++i)
  {
    ::std::copy(data.begin(), data.end(), oi);
    if(0==i%factor)
      rdbuf->pubsync();
  }

  ofs.flush();
  double rate = 500 / pt.elapsed();
  std::cout << rate << std::endl;
  return rate;
}

void count_avarage(const char* op_name, double (*fct)())
{
    double av_rate=0;
    const size_t repeat = 1;
    std::cout << "doing " << op_name << std::endl;
    for(size_t i=0; i<repeat; ++i)
        av_rate+=fct();

    std::cout << "average rate for " << op_name << ": " << av_rate/repeat 
            << "\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"
            << std::endl;
}


int main()
{
    count_avarage("copy via streambuf iterator", do_copy_via_streambuf);
    return 0;
}
1
ответ дан 14 December 2019 в 04:44
поделиться

Одна вещь, которую следует учитывать, это для создания собственной среды выполнения. Большинство компиляторов предоставляют исходный код для библиотеки времени выполнения (я был бы удивлен, если бы его не было в пакете C ++ Builder).

Это может потребовать много работы, но, возможно, они локализовали поддержку потоков на сделать что-то подобное простым. Например, встроенный компилятор системы, который я использую, предназначен для этого - у них есть задокументированные крючки для добавления подпрограмм блокировки. Однако возможно, что это может быть головной болью при обслуживании, даже если поначалу это окажется относительно простым.

1
ответ дан 14 December 2019 в 04:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: