Многопоточное объединение файлов (разделяемая память)
Допустим, у меня есть N файлов в таком формате:
Один файл выглядит так:
Для каждого времени есть некоторое количество данных с разными идентификаторами.
- time 1:
- data with id: 10
- data with id: 13
- data with id: 4
- time 2:
- data with id: 10
- data with id: 77
...etc
(за каждый раз, когда данные с идентификаторами от 1 до 1000 распределяются как-то (смешиваются) по этим N файлам)
Я хотел бы объединить все эти N файлов, чтобы у меня был один файл, который упорядочен:
Конечный файл:
- time 1:
- data with id: 1
- data with id: 2
- data with id: 3
- ...
- data with id: 1000
- time 2:
- data with id: 1
- data with id: 2
- data with id: 3
- ...
- data with id: 1000
...etc
Размер идентификатора данных 1-1000 составляет примерно 100 МБ, но у меня много раз, что составляет до 50 Гбайт данных.
Мое решение этой проблемы было бы таким, чтобы сделать это как можно быстрее:
Я использую T потоков на суперкомпьютерном узле (например, 1 компьютер с 24-48 ядрами) (например). Я выделил массив совместно используемой памяти для хранения всех данных с идентификаторами 1 - 1000 за один раз (также может быть больше, если мне нравится)
Процедура:
Шаг 1:
- Каждый поток имеет несколько файлов, которые он открывает и владеет. Затем каждый поток заполняет данные идентификаторов, которые он имеет в файлах, в общий массив.
Шаг 2:
- Когда все потоки окончательно обработаны один раз -> Поток 1 записывает этот массив в упорядоченном виде в окончательный файл.
Asdasd
- Мне было бы очень интересно, если это эффективно? Параллельное чтение не секвенировано в любом случае, так что оно вообще бесполезно? Я мог бы вычислить окончательный файл на локальном компьютере со сверхбыстрым SSD или на узле кластера с сетевым хранилищем (Lustres или Panasas Filesystems)
- Могу ли я снова использовать все потоки на шаге 2 для параллельной записи на диск, скажем, с помощью MPI IO (который поддерживает параллельную запись по смещению), или как еще этого достичь? -> стандартная библиотека C++?
Спасибо за любые вклады!
1 ответ
Ваш подход, вероятно, будет работать нормально для небольшого количества данных, но вы сделали один ранг центральной точкой связи здесь. Это не очень хорошо масштабируется.
Вы на правильном пути со своей частью 2: параллельная запись с использованием MPI-IO звучит как хороший подход для меня. Вот как это может произойти:
- Продолжайте, чтобы ваши T-процессы читали их входные данные.
- Я собираюсь предположить, что "id" плотно распределен. Я имею в виду, может ли процесс в этой коллекции файлов узнать, видит ли он
data with id: 4
что некоторые другие процессы имеют идентификаторы 1, 2, 3 и 5? Если это так, то каждый процесс знает, куда должны идти его данные. - Давайте также предположим, что каждый "данные" имеет фиксированный размер. Подход немного сложнее, если это не так.
Если вы не знаете максимального идентификатора и максимального временного шага, вам нужно будет немного пообщаться (MPI_Allreduce с MPI_MAX в качестве операции), чтобы найти это.
С помощью этих предварительных настроек вы можете установить MPI-IO "просмотр файла", возможно, используя MPI_Type_indexed
На уровне 0 это становится немного сложнее, потому что вам нужно добавить в список данных маркеры временного шага. Или вы можете определить формат файла с индексом временных шагов и сохранить этот индекс в верхнем или нижнем колонтитуле.
Код будет выглядеть примерно так:
for(i=0; i<nitems; i++)
datalen[i] = sizeof(item);
offsets[i] = sizeof(item)*index_of_item;
}
MPI_Type_create_indexed(nitems, datalen, offsets, MPI_BYTE, &filetype);
MPI_File_set_view(fh, 0, MPI_BYTE, filetype, "native", MPI_INFO_NULL);
MPI_File_write_all(fh, buffer, nitems*sizeof(item), MPI_BYTE, &status);
Все здесь очень важно: вы собираетесь создавать крайне несмежные, нерегулярные шаблоны доступа для каждого процессора MPI. Дайте библиотеке MPI-IO возможность оптимизировать этот запрос.
Также важно отметить, что представления файлов MPI-IO должны быть монотонно неубывающими, поэтому вам придется сортировать элементы локально, прежде чем записывать данные коллективно. Операции с локальной памятью имеют незначительную стоимость по сравнению с операцией ввода-вывода, поэтому обычно это не имеет большого значения.