Russian Qt Forum
Ноябрь 23, 2024, 07:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Запись в файл  (Прочитано 15275 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Март 16, 2012, 22:33 »

Добрый вечер

Есть вспомогательные расчеты которые выполняются одинаково неск раз. Естественно желание слить результаты на диск и потом грузить вместо того чтобы считать повторно. Но как это сделать для 2 или более ниток?

Порядок такой: есть массив матриц 9x9 пикселей, на них натравливается заданное число ниток N. Ок, посчитали начали след фазу (опять те же матрицы N нитками), опять требуется вспомогательный расчет что уже был на предыдущем шаге. Хммм.. и как загрузить?

Спасибо

Записан
V1KT0P
Гость
« Ответ #1 : Март 17, 2012, 00:45 »

Добрый вечер

Есть вспомогательные расчеты которые выполняются одинаково неск раз. Естественно желание слить результаты на диск и потом грузить вместо того чтобы считать повторно. Но как это сделать для 2 или более ниток?

Порядок такой: есть массив матриц 9x9 пикселей, на них натравливается заданное число ниток N. Ок, посчитали начали след фазу (опять те же матрицы N нитками), опять требуется вспомогательный расчет что уже был на предыдущем шаге. Хммм.. и как загрузить?

Спасибо
Что-то как-то не очень понятно расписано. Сделай класс для хранения результатов, и сделай его синглтоном. При запуске проги пусть загружает все данные из файла, при закрытии сохраняет в файл.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Март 17, 2012, 11:27 »

Что-то как-то не очень понятно расписано. Сделай класс для хранения результатов, и сделай его синглтоном. При запуске проги пусть загружает все данные из файла, при закрытии сохраняет в файл.
Речь идет о выполнении серии расчетов на 1 запуске. Псевдокод
Код
C++ (Qt)
// первый шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
CalcLayers(matr[i]);
CalcBounds(matr[i]);
}
 
//... какой-то не параллельный код
 
// второй шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
CalcLayers(matr[i]);   // опять нужен CalcLayers и он даст те же результаты что и на шаге 1
CalcInterior(matr[i]);
}
 
Записан
BRE
Гость
« Ответ #3 : Март 17, 2012, 11:45 »

Код
C++ (Qt)
// первый шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
data = CalcLayers(matr[i]);
SaveLayers( i, data );    // сохранили во внешнем хранилище данные, ключом является индекс
CalcBounds(matr[i]);
}
 
//... какой-то не параллельный код
 
// второй шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
data = ReadLayers( i );   // читаем из внешнего хранилища данные для нужного индекса
CalcInterior(matr[i]);
}
 

А внешним хранилищем может быть как файл с записями фиксированной длины для быстрого вычисления смещения до записи, так и база данных.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Март 17, 2012, 12:03 »

А внешним хранилищем может быть как файл с записями фиксированной длины для быстрого вычисления смещения до записи, так и база данных.
Вот так я и хочу. Правда фиксированной длины не получится, но не суть. Проблема в том что это работает только для 1 нитки  - тогда порядок чтения совпадает с записью. Но что делать если ниток 2 или более и они пишут/читают как/когда хотят Непонимающий
Записан
BRE
Гость
« Ответ #5 : Март 17, 2012, 12:10 »

Проблема в том что это работает только для 1 нитки  - тогда порядок чтения совпадает с записью.
Ты можешь свободно перемещаться по файлу с помощью seek. Одной нитке нужна запись с индексом 12 - переместились в то место файла и прочитали, второй с индексом 47 - переместились, прочитали.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Март 17, 2012, 12:16 »

Ты можешь свободно перемещаться по файлу с помощью seek. Одной нитке нужна запись с индексом 12 - переместились в то место файла и прочитали, второй с индексом 47 - переместились, прочитали.
Это очевидно, но даже по самым примерным прикидкам - мрачно. seek сбросит кэш файла, имеем некэшированный I/O который к тому же надо лочить. Обойдется дороже чем пересчитать. Думаю как бы соорудить свой файл для каждой нитки...
Записан
BRE
Гость
« Ответ #7 : Март 17, 2012, 12:17 »

Это очевидно, но даже по самым примерным прикидкам - мрачно. seek сбросит кэш файла, имеем некэшированный I/O который к тому же надо лочить. Обойдется дороже чем пересчитать. Думаю как бы соорудить свой файл для каждой нитки...
А ты его размапь в память.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Март 17, 2012, 12:21 »

А ты его размапь в память.
Не могу, так же как и просто хранить все результаты CalcLayers в памяти. Общий расход памяти не должен превышать заданный предел
Записан
BRE
Гость
« Ответ #9 : Март 17, 2012, 12:27 »

Не могу, так же как и просто хранить все результаты CalcLayers в памяти. Общий расход памяти не должен превышать заданный предел
Можно мапить нужными в данный момент области файла, окнами не большого размера.
Записан
evd
Гость
« Ответ #10 : Март 17, 2012, 12:36 »

Порядок расчета важен?
Код:
// первый шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
 data = CalcLayers(matr[i]);
 SaveIndex(i); //Сохраняем индекс
 SaveLayers( data ); //и данные
 CalcBounds(matr[i]);
}
 
//... какой-то не параллельный код
 
// второй шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
 index = ReadIndex(); //Считываем иднекс
 data = ReadLayers();   // и данные
 CalcInterior(matr[index]);
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Март 17, 2012, 12:52 »

Порядок расчета важен?
Написав parallel мы соглашаемся что вычисления могут выполняться в любом порядке

Код:
// второй шаг
#pragma omp parallel for
for (int i = 0; i < matr.size(); ++i) {
 index = ReadIndex(); //Считываем иднекс
 data = ReadLayers();   // и данные
 CalcInterior(matr[index]);
}
Ну ReadIndex/Layers придется защитить, но не вижу никакой ошибки. Спасибо
Записан
BRE
Гость
« Ответ #12 : Март 17, 2012, 17:30 »

Это для linux (думаю также будет работать и под маком), под венду переделывается за пару минут.

Код
C++ (Qt)
#include <QCoreApplication>
#include <QtConcurrentMap>
#include <QFutureWatcher>
#include <QFile>
#include <QThread>
#include <QDebug>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
 
static const int count = 10000;
static const int bufSize = sizeof( int );
 
static int pageSize;
 
struct Data
{
int handle;
int index;
};
 
bool writeData( const Data &data )
{
qDebug() << "Process index = " << data.index << "( thread id =" << QThread::currentThreadId() << ")";
 
off_t offsetHi = (data.index * bufSize) / pageSize;
off_t offsetLo = (data.index * bufSize) % pageSize;
 
void *address = mmap( 0, pageSize + bufSize, PROT_WRITE, MAP_SHARED, data.handle, offsetHi * pageSize );
if( address == MAP_FAILED )
{
qDebug() << "mmap error" << errno;
return false;
}
 
int *dst = static_cast<int *>( address + offsetLo );
*dst = data.index;
 
munmap( address, pageSize + bufSize );
 
return true;
}
 
bool readData( const Data &data )
{
off_t offsetHi = (data.index * bufSize) / pageSize;
off_t offsetLo = (data.index * bufSize) % pageSize;
 
void *address = mmap( 0, pageSize + bufSize, PROT_READ, MAP_SHARED, data.handle, offsetHi * pageSize );
if( address == MAP_FAILED )
{
qDebug() << "mmap error" << errno;
return false;
}
 
int *src = static_cast<int *>( address + offsetLo );
qDebug() << "Check index = " << data.index << (( *src == data.index )? "Ok" : "Error");
 
munmap( address, pageSize + bufSize );
 
return true;
}
 
int main( int argc, char *argv[] )
{
QCoreApplication app( argc, argv );
 
pageSize = sysconf( _SC_PAGESIZE );
 
QFile file( "data.bin" );
if( !file.open( QIODevice::ReadWrite ) )
{
qWarning() << "File open error";
return 1;
}
file.resize( bufSize * count );
 
QList<Data> data;
for( int i = 0; i < count; ++i )
{
Data d;
d.handle = file.handle();
d.index = i;
data.append( d );
}
 
qDebug() << "Write";
QFutureWatcher<bool> writer;
writer.setFuture( QtConcurrent::mapped( data, writeData ) );
writer.waitForFinished();
 
qDebug() << "Read";
QFutureWatcher<bool> reader;
reader.setFuture( QtConcurrent::mapped( data, readData ) );
reader.waitForFinished();
 
return 0;
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Март 18, 2012, 14:04 »

Это для linux (думаю также будет работать и под маком), под венду переделывается за пару минут.
С реализацией все отлично, но использование shared memory здесь нехорошо, т.к. это расход памяти, причем непредсказуемый. В данном проекте вообще прилагаются усилия чтобы параллельный код работал с как можно меньшим числом вызовов ОС.

Думал "у каждой нитки свой файл" - и тогда они могут читать/писать без локов. Но возникает проблема перекоса: на записи одна нитка может сделать большой файл, другая маленький, а чтение это унаследует. Перебросить из одного файла в другой - ну можно, но все-таки усложнение
Записан
BRE
Гость
« Ответ #14 : Март 18, 2012, 14:12 »

но использование shared memory здесь нехорошо, т.к. это расход памяти, причем непредсказуемый.
Что значит не предсказуемый? Кем не предсказуемый? В примере все размеры указаны. Размер окна чуть больше размера страницы на каждый поток (реально будет использоваться две), не много правда? Тебе стоит разобраться с работай разделяемой памяти на уровне системы.

В данном проекте вообще прилагаются усилия чтобы параллельный код работал с как можно меньшим числом вызовов ОС.
Два системный вызова это конечно перебор, посмотрим на твое решение.
Судя по этому:
Цитировать
Думал "у каждой нитки свой файл" - и тогда они могут читать/писать без локов. Но возникает проблема перекоса: на записи одна нитка может сделать большой файл, другая маленький, а чтение это унаследует. Перебросить из одного файла в другой - ну можно, но все-таки усложнение
оно будет заметно проще.
« Последнее редактирование: Март 18, 2012, 14:23 от BRE » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.275 секунд. Запросов: 23.