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...
Пока на собственное сообщение не было ответов, его можно удалить.