2016-12-01 4 views
6

В настоящее время я работаю над проектом, где у меня есть большой текстовый файл (15+ ГБ), и я пытаюсь запустить функцию в каждой строке файла. Чтобы ускорить выполнение задачи, я создаю 4 потока и пытаюсь заставить их прочитать файл в одно и то же время. Это похоже на то, что у меня есть:Есть ли способ атомного чтения строки из файла C++

#include <stdio.h> 
#include <string> 
#include <iostream> 
#include <stdlib.h> 
#include <thread> 
#include <fstream> 

void simpleFunction(*wordlist){ 
    string word; 
    getline(*wordlist, word); 
    cout << word << endl; 
} 
int main(){ 
    int max_concurrant_threads = 4; 
    ifstream wordlist("filename.txt"); 
    thread all_threads[max_concurrant_threads]; 

    for(int i = 0; i < max_concurrant_threads; i++){ 
     all_threads[i] = thread(simpleFunction,&wordlist); 
    } 

    for (int i = 0; i < max_concurrant_threads; ++i) { 
     all_threads[i].join(); 
    } 
    return 0; 
} 

Функция GetLine (наряду с «* словник >> слово»), кажется, увеличиваем указатель и прочитать значение в 2 этапа, как я буду регулярно получать:

Item1 
Item2 
Item3 
Item2 

назад.

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

Я не мог найти ничего о fstream и атомарности getline. Если есть атомная версия readline или даже простой способ использовать блокировки для достижения того, что я хочу, я все уши.

Заранее благодарен!

+1

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

+4

Я не могу поверить, что это невозможно. Даже с помощью 'read' syscalls. Однако это неправильный способ сделать это: вы должны дать вашим потокам линию для обработки; то у вас нет общего ресурса. –

+1

Коэффициенты высоки, что одновременное чтение в тот же файл очень сильно замедлит работу. Существует один диск для чтения, и вы хотите выполнять очень мелкозернистые обращения в разных местах с синхронизацией. –

ответ

4

Правильный способ сделать это будет блокировка файла, что предотвратит использование всех других процессов. См. Wikipedia: File locking. Это, вероятно, слишком медленно для вас, потому что вы читаете только одну строку за раз. Но если вы читали, например, 1000 или 10000 строк во время каждого вызова функции, это может быть наилучшим способом его реализации.

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

void simpleFunction(*wordlist){ 
    static std::mutex io_mutex; 
    string word; 
    { 
     std::lock_guard<std::mutex> lock(io_mutex); 
     getline(*wordlist, word); 
    } 
    cout << word << endl; 
} 

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

class FileReader { 
public: 
    // This runs in its own thread 
    void readingLoop() { 
     // read lines to storage, unless there are too many lines already 
    } 

    // This is called by other threads 
    std::string getline() { 
     std::lock_guard<std::mutex> lock(storageMutex); 
     // return line from storage, and delete it 
    } 
private: 
    std::mutex storageMutex; 
    std::deque<std::string> storage; 
}; 
+0

Спасибо за помощь! Я тестировал с использованием мьютекса в первом примере, поскольку его было проще реализовать быстро. Он правильно прочитал файл и дал заметное ускорение от 1 ядра до 2 ядер, но после этого сплющился. Я полагаю, что блокировки из 3+ потоков замедляют его. Я предполагаю, что второй результат будет более масштабируемым, и я буду реализовывать его позже. Еще раз спасибо! – tuchfarber