[win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 10:54
Оценка:
Надо ускорить запись 200-300Мб данных в файл, для этого подойдет такое решение:
— в основном потоке данные будут быстро добавляться в очередь, во вспомогательном — медленно писаться на диск,
когда данные заканчиваются, основной поток информирует об этом вспомогательный, но не ждет конца записи.

Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?
In Zen We Trust
Re: [win] запись в файл в фоновом потоке
От: uzhas Ниоткуда  
Дата: 30.04.11 10:56
Оценка: 1 (1)
Здравствуйте, Abyx, Вы писали:

A>Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?

http://msdn.microsoft.com/en-us/library/aa365683(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa365198(v=vs.85).aspx
Re[2]: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 11:07
Оценка:
Здравствуйте, uzhas, Вы писали:

A>>Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?

U>http://msdn.microsoft.com/en-us/library/aa365683(v=vs.85).aspx
U>http://msdn.microsoft.com/en-us/library/aa365198(v=vs.85).aspx

да, я это читал, только как это применить к моей проблеме?
In Zen We Trust
Re: [win] запись в файл в фоновом потоке
От: Temnikov Россия  
Дата: 30.04.11 11:28
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Надо ускорить запись 200-300Мб данных в файл, для этого подойдет такое решение:

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

A>Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?



// шаблонный класс реализующий очередь в паралельном потоке
template <typename T> 
class CObjectQueueImpl
{
public:
    CObjectQueueImpl() : m_qFrames()
    {
        DWORD dwThreadID;
        m_hShutdownEvent = ::CreateEvent(NULL, false, false, NULL);
        m_hPutEvent = ::CreateEvent(NULL, false, false, NULL);
        m_hThread = ::CreateThread(NULL, 0, ThrdProc, this, 0, &dwThreadID);
    }
    ~CObjectQueueImpl()
    {
        if(m_hShutdownEvent)
            SetEvent(m_hShutdownEvent);
        WaitForSingleObject(m_hThread, INFINITE);
        CloseHandle(m_hThread);
    }
    bool ExtractFromQueue(T& Obj)
    {    
        if(m_qFrames.empty())
            return false;
        m_cs.Lock();
        Obj = m_qFrames.front();
        m_qFrames.pop();
        m_cs.Unlock();
        return true;
    }

    bool PutToQueue(const T* pObj)
    {
        if(!m_hPutEvent)
            return false;
        m_cs.Lock();
        m_qFrames.push(*pObj);
        m_cs.Unlock();
        SetEvent(m_hPutEvent);
        return true;
    }
    virtual void OnQueueNewObject()=0;
private:
    void WorkProc() throw()
    {
        ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        HANDLE Handles[] = {m_hShutdownEvent, m_hPutEvent};
        DWORD dwCount = sizeof(Handles)/sizeof(Handles[0]);
        while (::WaitForMultipleObjects(dwCount, Handles, FALSE, INFINITE) != WAIT_OBJECT_0)
        {
            ResetEvent(m_hPutEvent);
            OnQueueNewObject();
        }
        ::CloseHandle(m_hShutdownEvent);
        ::CloseHandle(m_hPutEvent);
        m_hShutdownEvent = m_hPutEvent = NULL;
        ::CoUninitialize();
    }

    static DWORD WINAPI ThrdProc(void* pv) throw()
    {
        CObjectQueueImpl<T>* p = static_cast<CObjectQueueImpl<T>*>(pv);
        p->WorkProc();
        return 0;
    }

    std::queue<T> m_qFrames;
    CComAutoCriticalSection m_cs;
    HANDLE m_hPutEvent;
    HANDLE m_hShutdownEvent;
    HANDLE m_hThread;
};


Наследуем класс там где необходимо иметь параллельный поток с обработкой:
public CObjectQueueImpl<XXX>, где ХХХ — тип данных который будет передаваться в поток.
Переопределяем в классе метод OnQueueNewObject — вызывается из параллельного потока когда в него поступает новый объект.

В методе OnQueueNewObject делаем:

void CLASSNAME::OnQueueNewObject()
{
    XXX Param;
    while(ExtractFromQueue(Param))
    {
           DO SOMETHONG
    }
}


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

Есть недостатки у данного класса, но допиливать уже нет необходимости в тех задачах где он используется у меня.
Re[2]: [win] использование
От: Temnikov Россия  
Дата: 30.04.11 11:31
Оценка:
Забыл добавить. Чтобы передать что то в параллельный поток необходимо вызвать метод PutToQueue.

XXX Param;
PutToQueue(&Param);
Re: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 11:46
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?


тег [win] в названии темы означает только что меня устроит платформозависимое решение,
но не означает что решение обязательно должно быть на голом WinAPI.

кроме того, в этой задаче мне важнее всего быстродействие добавления данных в основном потоке,
и у меня есть подозрения что любые решения использующие WinAPI будут проигрывать кроссплатформенным решениям не взаимодействующим с ОС.
In Zen We Trust
Re[2]: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 11:50
Оценка:
Здравствуйте, Temnikov, Вы писали:
T> m_cs.Lock();
...
T> m_cs.Unlock();
T> SetEvent(m_hPutEvent);

есть подозрение что захват критической секции и установка события будут создавать огромный оверхед на добавление данных в очередь.
In Zen We Trust
Re[3]: [win] запись в файл в фоновом потоке
От: Temnikov Россия  
Дата: 30.04.11 11:58
Оценка:
A>Здравствуйте, Temnikov, Вы писали:
T>> m_cs.Lock();
A>...
T>> m_cs.Unlock();
T>> SetEvent(m_hPutEvent);

A>есть подозрение что захват критической секции и установка события будут создавать огромный оверхед на добавление данных в очередь.


Прямо таки огромный? Используйте lock-free контейнер, останется оверхед только от вызова события. Хотя можно и от него отказаться, если данные будут доставаться из очереди, постоянно в вечном цикле, только с проверкой завершения потока.
Вы ни слова не сказали какие требования предъявляются.
Re[2]: upd: [win] запись в файл в фоновом потоке
От: Аноним  
Дата: 30.04.11 12:12
Оценка:
A> кроме того, в этой задаче мне важнее всего быстродействие добавления данных в основном потоке,

возьмите наивный локфри стек отсюда http://en.wikipedia.org/wiki/ABA_problem. Для одного производителя и одного потребителя АБА не проявится, кода строк 15 там. Тормозов будет минимум.

Но вообще вместо фразы 'есть подозрения' обычно лучше написать бенчмарк.
Re[2]: upd: [win] запись в файл в фоновом потоке
От: ononim  
Дата: 30.04.11 12:15
Оценка:
A>кроме того, в этой задаче мне важнее всего быстродействие добавления данных в основном потоке,
A>и у меня есть подозрения что любые решения использующие WinAPI будут проигрывать кроссплатформенным решениям не взаимодействующим с ОС.
а вот здесь ваша логика в корне ошибочна
Как много веселых ребят, и все делают велосипед...
Re[3]: upd: [win] запись в файл в фоновом потоке
От: Аноним  
Дата: 30.04.11 12:20
Оценка:
Здравствуйте, ononim, Вы писали:

A>>кроме того, в этой задаче мне важнее всего быстродействие добавления данных в основном потоке,

A>>и у меня есть подозрения что любые решения использующие WinAPI будут проигрывать кроссплатформенным решениям не взаимодействующим с ОС.
O>а вот здесь ваша логика в корне ошибочна

нет там логики, есть подозрения
Re: [win] запись в файл в фоновом потоке
От: okman Беларусь https://searchinform.ru/
Дата: 30.04.11 12:52
Оценка:
Здравствуйте, Abyx.

А Вы точно ускоряете там где надо ?
Скорость записи на диск все равно постоянна, и не зависит от разделения логики
программы на сигнальный и пишущий потоки, ну разве что время отклика уменьшается.

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

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

Могу посоветовать asio из boost — там вроде эти же самые механизмы и используются.
Re[3]: [win] запись в файл в фоновом потоке
От: uzhas Ниоткуда  
Дата: 30.04.11 12:56
Оценка: 1 (1)
Здравствуйте, Abyx, Вы писали:

A>да, я это читал, только как это применить к моей проблеме?

тогда мне не ясно что вам не ясно. там вполне доходчиво все объясняется
коротко : система взяла на себя функции обслуживать асинхронную запись и вместо создания своих потоков можно воспользоваться уже готовыми механизмами:

while (данные есть)
{

  1. писатель берет порцию данных (например, 100 Кб) и пихает в систему, используя асинхронное API
  2. система берет данные и обязуется их однажды записать на диск.
далее управление передается клиенту и он, не дожидаясь окончания записи, уходит в цикл
}

Wait(система все скинула на диск)

Re[4]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 12:59
Оценка:
Здравствуйте, Аноним, Вы писали:

A>>>кроме того, в этой задаче мне важнее всего быстродействие добавления данных в основном потоке,

A>>>и у меня есть подозрения что любые решения использующие WinAPI будут проигрывать кроссплатформенным решениям не взаимодействующим с ОС.
O>>а вот здесь ваша логика в корне ошибочна

А>нет там логики, есть подозрения


я знаю что генерация данных для записи происходит очень быстро (сотни тактов) и я знаю что функции WinAPI в лучшем случае работают примерно столько же (критические секции — порядка сотни тактов; SetEvent, HeapAlloc — порядка тысячи тактов)

считайте что код, генерирующий данные выглядит так
for(int i = 0; i != 100*1000*1000; ++i)
{
    char buf[16];
    _itoa(rand(), buf, 16);
    write_data(buf, strlen(buf));
}


желательно чтобы время работы write_data было не более 10% от времени работы rand() + itoa()
In Zen We Trust
Re[4]: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 13:07
Оценка:
Здравствуйте, uzhas, Вы писали:

U> писатель берет порцию данных (например, 100 Кб) и пихает в систему, используя асинхронное API

чтобы накопить эти 100 Кб, нужен какой-то код, наверное класс потока, где такой взять?

U>Wait(система все скинула на диск)

а вот этого в основном потоке не должно быть вообще, по условию задачи
In Zen We Trust
Re[5]: [win] запись в файл в фоновом потоке
От: uzhas Ниоткуда  
Дата: 30.04.11 13:20
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, uzhas, Вы писали:


U>> писатель берет порцию данных (например, 100 Кб) и пихает в систему, используя асинхронное API

A>чтобы накопить эти 100 Кб, нужен какой-то код, наверное класс потока, где такой взять?

в программе лишь один поток, второй не нужен, и класс потока вам не нужен

U>>Wait(система все скинула на диск)

A>а вот этого в основном потоке не должно быть вообще, по условию задачи
Wait делается в самом-самом конце всей записывающей программы (когда заветные 500Mb будут отправлены на запись и данных для записи больше не будет)
вам нужно внимательнее все прочитать и осмыслить, в том числе документацию на msdn, куда ведут вышеупомянутые ссылки

зы: я даже боюсь вам советовать в boost::io_service из-за странных вопросов
Re[6]: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 13:27
Оценка:
Здравствуйте, uzhas, Вы писали:

A>>чтобы накопить эти 100 Кб, нужен какой-то код, наверное класс потока, где такой взять?

U>в программе лишь один поток, второй не нужен, и класс потока вам не нужен
здесь под потоком имелся ввиду "stream"

U>>>Wait(система все скинула на диск)

A>>а вот этого в основном потоке не должно быть вообще, по условию задачи
U>Wait делается в самом-самом конце всей записывающей программы (когда заветные 500Mb будут отправлены на запись и данных для записи больше не будет)
не понял насчет "записывающей программы" %)
еще раз повторю, поток который выдает данные для записи, окончания записи ждать не должен. по условию задачи.
то что процесс перед завершением должен ждать завершения фоновых потоков — это отдельный вопрос.

U>зы: я даже боюсь вам советовать в boost::io_service из-за странных вопросов

такого нет. есть boost::asio::io_service
In Zen We Trust
Re[5]: upd: [win] запись в файл в фоновом потоке
От: okman Беларусь https://searchinform.ru/
Дата: 30.04.11 13:30
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>считайте что код, генерирующий данные выглядит так

A>
A>for(int i = 0; i != 100*1000*1000; ++i)
A>{
A>    char buf[16];
A>    _itoa(rand(), buf, 16);
A>    write_data(buf, strlen(buf));
A>}
A>


Если так, то здесь налицо проблема маленького буфера.
Никакие алгоритмы и распараллеливания не помогут, если данные пишутся в файл по нескольку
байт за один присест. Тут нужно расширять файловый буфер (хотя бы в виде обертки над WriteFile).
Положительный результат наблюдался неоднократно.
Re[7]: [win] запись в файл в фоновом потоке
От: uzhas Ниоткуда  
Дата: 30.04.11 13:50
Оценка:
Здравствуйте, Abyx, Вы писали:


A>еще раз повторю, поток который выдает данные для записи, окончания записи ждать не должен. по условию задачи.


то есть вам важна скорость генерации данных, а не запись их в файл
тогда вам нужна lock-free очередь для переброски данных из главного потока в дополнительный (пишущий)
у вас один писатель в очередь и один потребитель, поэтому задача очень упрощается
покопайте буст\гугл. WinAPI вряд ли вам поможет
Re[6]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 30.04.11 14:04
Оценка:
Здравствуйте, okman, Вы писали:

O>Тут нужно расширять файловый буфер (хотя бы в виде обертки над WriteFile).

так в этом и есть вопрос — какая штука будет накапливать данные и потом в фоновом потоке писать в файл.
In Zen We Trust
Re[7]: upd: [win] запись в файл в фоновом потоке
От: ononim  
Дата: 30.04.11 14:12
Оценка:
O>>Тут нужно расширять файловый буфер (хотя бы в виде обертки над WriteFile).
A>так в этом и есть вопрос — какая штука будет накапливать данные и потом в фоновом потоке писать в файл.
1) выделяете большой буфер
2) поток-заполнитель потихоньку заполяет его своими данными
3) как только буфер заполнен наполовину — поток заполнитель сигнализирует потоку писателю что пора бы начинать работать (setevent(data_ready))
4) если буфер заполнен полностью — поток заполнитель дожидается окончания работы потока-писателя (waitfor(datawritten))
5) поток писатель крутится в цикле в котором ждет data_ready, при дожидании — записывает все имеющиеся в буфере данные и сигналит datawritten.
Как много веселых ребят, и все делают велосипед...
Re[7]: upd: [win] запись в файл в фоновом потоке
От: BulatZiganshin  
Дата: 02.05.11 20:12
Оценка:
Здравствуйте, Abyx, Вы писали:

O>>Тут нужно расширять файловый буфер (хотя бы в виде обертки над WriteFile).

A>так в этом и есть вопрос — какая штука будет накапливать данные и потом в фоновом потоке писать в файл.

я понимаю, вы как все ньюбы хотите оптимизацию любой ценой. но я вам советую начать с управления буфером файла — 4 кб, 64 кб, 512 кб и один поток

и только если скорости не хватит — тогда уже переходить к очереди буферов таких размеров. тогда вам будет наплевать на оверхид синхронизации. и чтобы понять пределы оптимизации — измерить время генерации данных без записи и наоборот. в лучшем случае вы получите ускорение вдвое, но afaik винда и сама неплохо кеширует записываемые данные, быстро отдавая управление назад, так что второй поток даст копеечный выигрыш
Люди, я люблю вас! Будьте бдительны!!!
Re[8]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 02.05.11 22:17
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>я понимаю, вы как все ньюбы

необоснованное обвинение в нубстве — вещь человека не красящая.

я расстроен =\ куча ответов только ради того чтобы лучше раскрыть проблему, ни одного толкового решения, и тут вылазите вы со своими ошибочными предположениями.

вот псевдокод того я хочу оптимизировать
void save_data(all_data_t allData)
{
   data.lock();
   
   // сериализация в непрерывный буфер памяти размером 500Мб
   // примерно 2 секунды (измерялось GetTickCount)
   memory_stream_t stream(global_500Mb_buffer);
   serialize(stream, data);

   data.unlock();

   // запись примерно 200-300Мб сериализованных данных в файл
   // примерно 2 секунды
   write_to_file(..., stream); // один вызов WriteFile
}

данные лочатся на две секунды, и это МНОГО. юзеры при этом ощущают внезапную паузу. Если воспользоваться этим советом,
BZ>советую начать с управления буфером файла — 4 кб, 64 кб, 512 кб и один поток
будет не менее четырех секунд, это *слишком много*

код сериализации (serialize) менять нельзя, но можно менять код архива (stream).

memory_stream_t оптимизирован до предела, в том числе за счет большого непрерывного буфера (убраны проверки на конец буфера),
однако буфер слишком большой и слишком непрерывный (для 32разрядного процесса).

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

BZ>и чтобы понять пределы оптимизации — измерить время генерации данных без записи и наоборот

сами замеряли сколько времени пишется на кусок памяти в пару сотен Мб ?
BZ>в лучшем случае вы получите ускорение вдвое
с вашим ценным советом — именно так. ускорю сериализацию в сто раз, и получу результирующее ускорение вдвое.
In Zen We Trust
Re[9]: upd: [win] запись в файл в фоновом потоке
От: Хвост  
Дата: 02.05.11 22:29
Оценка:
Здравствуйте, Abyx, Вы писали:

в чём сложность позвать save_data в фоновом потоке?
People write code, programming languages don't.
Re[10]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 08:23
Оценка:
Здравствуйте, Хвост, Вы писали:

Х>Здравствуйте, Abyx, Вы писали:


Х>в чём сложность позвать save_data в фоновом потоке?


ни в чем, только он от этого станет "основным".
тот поток который работает с данными — основной, другие потоки — фоновые
In Zen We Trust
Re[9]: upd: [win] запись в файл в фоновом потоке
От: uzhas Ниоткуда  
Дата: 03.05.11 08:42
Оценка: 1 (1) +1 -1
Здравствуйте, Abyx, Вы писали:

A>я расстроен =\ куча ответов только ради того чтобы лучше раскрыть проблему, ни одного толкового решения, и тут вылазите вы со своими ошибочными предположениями.

это связано с плохо сформулированной задачей

очередной тычок пальцем:
void save_data(all_data_t data)
{
   data.lock();
   
   // сериализация в непрерывный буфер памяти размером 500Мб
   // примерно 2 секунды (измерялось GetTickCount)
   memory_stream_t stream(global_500Mb_buffer);
   serialize(stream, data);

   data.unlock();

   // запись примерно 200-300Мб сериализованных данных в файл
   // примерно 2 секунды в другом потоке
   write_to_file_in_different_thread(..., stream); // один вызов WriteFile в другом потоке
}
Re[10]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 13:09
Оценка: :)
Здравствуйте, uzhas, Вы писали:

U>это связано с плохо сформулированной задачей

что непонятно в задаче?

A>Надо ускорить запись 200-300Мб данных в файл, для этого подойдет такое решение:

A>в основном потоке данные будут быстро добавляться в очередь, во вспомогательном — медленно писаться на диск,
A>когда данные заканчиваются, основной поток информирует об этом вспомогательный, но не ждет конца записи.

то что сотни Мб пишутся на диск за единицы секунд и изменение производительности на десяток-другой процентов заметно для юзера?
то что данные генерируются быстрее чем пишутся на диск? — см. 2ю строчку
то что окончания записи на диск можно не ждать и это по позволяет ускорить запись за счет выноса работы с диском в отдельный поток?

наверное надо было сразу упомянуть что данные могут писаться небольшими кусками, байт по 100-300
In Zen We Trust
Re[11]: upd: [win] запись в файл в фоновом потоке
От: const_volatile  
Дата: 03.05.11 13:56
Оценка:
Здравствуйте, Abyx, Вы писали:

A>то что сотни Мб пишутся на диск за единицы секунд и изменение производительности на десяток-другой процентов заметно для юзера?

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

A>наверное надо было сразу упомянуть что данные могут писаться небольшими кусками, байт по 100-300


у меня есть реализация win32 overlapped i/o с интерфейсом std::streambuf. НЕ thread-safe, писать может только один поток, но операции записи не блокируют поток. готов поделиться за $200. лицензия BSD-like. за дополнительные $200 сделаю порт под линуксовый aio.
Re[11]: upd: [win] запись в файл в фоновом потоке
От: okman Беларусь https://searchinform.ru/
Дата: 03.05.11 14:20
Оценка:
Здравствуйте, Abyx.

Правильный ответ на эту задачу, в той форме, в какой она была сформулирована, был дан самым первым.
Я не знаю, что еще нужно придумывать, если есть асинхронные операции ввода-вывода.
Фактически, не нужен никакой второй поток, поскольку ReadFile/WriteFile возвращают управление
сразу же после вызова, ни разбивка на маленькие порции по этой же причине.
Там есть несколько тонкостей, которые требуют отдельного внимания, но их вполне можно было
решить за те несколько дней, пока данная тема висит на первой странице форумов.
Re[12]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 14:26
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>у меня есть реализация win32 overlapped i/o с интерфейсом std::streambuf. НЕ thread-safe, писать может только один поток, но операции записи не блокируют поток. готов поделиться за $200. лицензия BSD-like. за дополнительные $200 сделаю порт под линуксовый aio.


вы ее на этой задаче тестировали?
In Zen We Trust
Re[12]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 14:34
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, Abyx.


O>Правильный ответ на эту задачу, в той форме, в какой она была сформулирована, был дан самым первым.

O>Я не знаю, что еще нужно придумывать, если есть асинхронные операции ввода-вывода.
O>Фактически, не нужен никакой второй поток, поскольку ReadFile/WriteFile возвращают управление
O>сразу же после вызова, ни разбивка на маленькие порции по этой же причине.
O>Там есть несколько тонкостей, которые требуют отдельного внимания, но их вполне можно было
O>решить за те несколько дней, пока данная тема висит на первой странице форумов.

в первом посте был вопрос.
A>Есть ли для этого какие-то готовые библиотеки\функции WinAPI ?

я хочу библиотеку, или функцию которая ее заменит (типа libcurl vs URLDownloadToFile),
а мне предлагают писать велосипед.

что мне толку с голых ReadFile\WriteFile если к ним надо самому писать буферизацию??

да, ReadFile\WriteFile сразу возвращают управление, но кто и где будет удалять память? если без 2го потока — то ждать в основном потоке?
In Zen We Trust
Re[13]: upd: [win] запись в файл в фоновом потоке
От: const_volatile  
Дата: 03.05.11 14:39
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, const_volatile, Вы писали:


_>>у меня есть реализация win32 overlapped i/o с интерфейсом std::streambuf. НЕ thread-safe, писать может только один поток, но операции записи не блокируют поток. готов поделиться за $200. лицензия BSD-like. за дополнительные $200 сделаю порт под линуксовый aio.

A>вы ее на этой задаче тестировали?

класс используется в боевом режиме в нескольких real-world сервисах и приложениях. я могу написать стресс-тест по твоим спецификациям, но это увеличит цену еще на $50. встречное предложение — ты пишешь тест используя интерфейс std::streambuf, я прогоняю его у себя.
Re: [win] запись в файл в фоновом потоке
От: SSSerge Украина  
Дата: 03.05.11 15:04
Оценка:
http://www.codeproject.com/KB/winsdk/AsyncFile.aspx
Видели?
Re[14]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 15:25
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>Здравствуйте, Abyx, Вы писали:


A>>Здравствуйте, const_volatile, Вы писали:


_>>>у меня есть реализация win32 overlapped i/o с интерфейсом std::streambuf. НЕ thread-safe, писать может только один поток, но операции записи не блокируют поток. готов поделиться за $200. лицензия BSD-like. за дополнительные $200 сделаю порт под линуксовый aio.

A>>вы ее на этой задаче тестировали?

_>класс используется в боевом режиме в нескольких real-world сервисах и приложениях. я могу написать стресс-тест по твоим спецификациям, но это увеличит цену еще на $50. встречное предложение — ты пишешь тест используя интерфейс std::streambuf, я прогоняю его у себя.


ох... я еще должен писать тесты для кода который скорей всего не решает задачу %)

вот кусок моего кода который я использую сейчас
ваш должен быть незначительно медленнее, процентов на 10-20, и не использовать непрерывный буфер 800Мб

#include <cstdlib>
#include <iostream>
#include <Windows.h>

namespace abyx_code
{
    static const char g_hex_table[] = "0123456789abcdef";

    char* int2hex_w(unsigned value, char* buf)
    {
        buf[0] = g_hex_table[(value >> 12) & 0x0F];
        buf[1] = g_hex_table[(value >> 8) & 0x0F];
        buf[2] = g_hex_table[(value >> 4) & 0x0F];
        buf[3] = g_hex_table[value & 0x0F];
        return buf + 4;
    }

    struct scp_builder
    {
        char* pos;
        scp_builder(char* pos) : pos(pos) {}
        char* getPos() const { return pos; }

        scp_builder& str(char c)
        {
            *pos++ = c;
            return *this;
        }

        template<size_t M>
        scp_builder& str(const char (&text)[M])
        {
            static const auto N = M - 1;
            static_assert(N < 16, "string is too long");
            static_assert(N > 1, "string is too short");
            auto pos1 = (DWORD*)pos;
            auto text1 = (const DWORD*)text;
            pos1[0] = text1[0];
#pragma warning(push)
#pragma warning(disable:4127 6326)

            if(N > 4)
            {
                pos1[1] = text1[1];
                if(N > 8)
                {
                    pos1[2] = text1[2];
                    if(N > 12)
                    {
                        pos1[3] = text1[3];
                    }
                }
            }
#pragma warning(pop)
            pos += N;
            return *this;
        }

        scp_builder& word(WORD n)
        {
            *pos++ = '0';
            pos = int2hex_w(n, pos);
            return *this;
        }
    };

}

// test data generator
int get_data_word()
{
    static unsigned seed = 0;
    return seed = seed * 0x8088405 + 1, seed >> 16;
}

int main()
{
    auto buf = new char[800 * 1000 * 1000];

    auto t0 = GetTickCount();
    abyx_code::scp_builder builder(buf);
    for(auto i = 0; i != 100 * 1000 * 1000; ++i)
    {
        auto dataItem = get_data_word();
        builder.str("0x").word(dataItem).str(',');
    }
    auto t1 = GetTickCount();
    std::cout << "generation " << t1 - t0 << std::endl;
    
    auto t2 = GetTickCount();
    auto hFile = CreateFileA("temp.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, 0);
    DWORD nWritten;
    WriteFile(hFile, buf, builder.getPos() - buf, &nWritten, NULL);
    CloseHandle(hFile);
    auto t3 = GetTickCount();
    
    std::cout << "writing " << t3 - t2 << std::endl;
    std::cout << "total " << (t3 - t2) + (t1 - t0) << std::endl;
}


если у вас std::streambuf, то наверное вы будете использовать std::ostream
удачи =)
In Zen We Trust
Re[15]: upd: [win] запись в файл в фоновом потоке
От: const_volatile  
Дата: 03.05.11 16:14
Оценка:
Здравствуйте, Abyx, Вы писали:

A> auto buf = new char[800 * 1000 * 1000];


а принципиально создавать буфер в памяти? может проще создать memory-mapped файл и "писать" в него? платформно-независимый интерфейс есть в boost::iostreams.
Re[16]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 16:45
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>Здравствуйте, Abyx, Вы писали:


A>> auto buf = new char[800 * 1000 * 1000];


_>а принципиально создавать буфер в памяти? может проще создать memory-mapped файл и "писать" в него? платформно-независимый интерфейс есть в boost::iostreams.


принципиально избавиться от этого большого непрерывного буфера
In Zen We Trust
Re[17]: upd: [win] запись в файл в фоновом потоке
От: const_volatile  
Дата: 03.05.11 16:48
Оценка:
Здравствуйте, Abyx, Вы писали:

_>>а принципиально создавать буфер в памяти? может проще создать memory-mapped файл и "писать" в него? платформно-независимый интерфейс есть в boost::iostreams.

A>принципиально избавиться от этого большого непрерывного буфера

тогда memory-mapped file самое простое решение.
Re[18]: upd: [win] запись в файл в фоновом потоке
От: Abyx Россия  
Дата: 03.05.11 16:53
Оценка:
Здравствуйте, const_volatile, Вы писали:

_>Здравствуйте, Abyx, Вы писали:


_>>>а принципиально создавать буфер в памяти? может проще создать memory-mapped файл и "писать" в него? платформно-независимый интерфейс есть в boost::iostreams.

A>>принципиально избавиться от этого большого непрерывного буфера

_>тогда memory-mapped file самое простое решение.


а чем он лучше большого непрерывного буфера?

какбэ проблема буфера в том, что он занимает 10-20% адресного пространства, и его надо постоянно держать выделенным, потому что если его удалить, есть шанс что память фрагментируется так что его потом уже нельзя будет снова выделить.
In Zen We Trust
Re[19]: upd: [win] запись в файл в фоновом потоке
От: const_volatile  
Дата: 03.05.11 18:08
Оценка:
Здравствуйте, Abyx, Вы писали:

A>>>принципиально избавиться от этого большого непрерывного буфера

_>>тогда memory-mapped file самое простое решение.
A>а чем он лучше большого непрерывного буфера?
A>какбэ проблема буфера в том, что он занимает 10-20% адресного пространства, и его надо постоянно держать выделенным, потому что если его удалить, есть шанс что память фрагментируется так что его потом уже нельзя будет снова выделить.

если макс. объем данных известен, то через CreateFileMapping создаётся доступ к этому объёму, а в адресное пространство процесса через MapViewOfFile "проецируются" окна по N (нет, N мало, лучше M) байт. если знаком с потрохами std::streambuf, то проще всего это сделать через него, достаточно перегрузить overflow() и xsputn(). если нет — можно написать и свой интерфейс к такому буферу, но советую не изобретать велосипед и изучить стандартную библиотеку. я это, в общем-то к тому, что любые доступные в сети (такие как boost::iostreams) решения твоей задачи так или иначе требуют обработки напильником.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.