2016-12-01 17 views
6

Tôi hiện đang làm việc với một tệp văn bản lớn (15+ GB) và tôi đang cố gắng chạy một hàm trên mỗi dòng của tệp. Để tăng tốc nhiệm vụ, tôi tạo 4 chủ đề và cố gắng để họ đọc tập tin cùng một lúc. Điều này tương tự với những gì tôi có:Có cách nào để đọc nguyên tử một dòng từ một tệp 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; 
} 

Chức năng getline (cùng với "* wordlist >> Từ") dường như để tăng con trỏ và đọc giá trị trong 2 bước, như tôi sẽ thường xuyên nhận được:

Item1 
Item2 
Item3 
Item2 

quay lại.

Vì vậy, tôi đã tự hỏi nếu có một cách để đọc nguyên tử một dòng của tập tin? Việc tải nó vào một mảng đầu tiên sẽ không hoạt động vì tệp quá lớn và tôi không muốn tải tệp theo từng phần tại một thời điểm.

Tôi không thể tìm thấy bất kỳ điều gì liên quan đến fstream và atomicity của getline đáng buồn. Nếu có một phiên bản nguyên tử của readline hoặc thậm chí là một cách đơn giản để sử dụng khóa để đạt được những gì tôi muốn, tôi là tất cả các tai.

Cảm ơn trước!

+1

Mỗi dòng có cùng kích thước không? Nếu không thì không, bạn không thể thực sự làm điều đó mà không cần đồng bộ hóa (ví dụ: semaphores hoặc mutexes). –

+4

Tôi không thể thực hiện điều đó bằng cách sử dụng khóa. Ngay cả chỉ với 'read' syscalls. Tuy nhiên, nó không phải là cách đúng để làm điều đó: Bạn nên cung cấp cho chủ đề của bạn một dòng để xử lý; thì bạn không có tài nguyên được chia sẻ. –

+1

Tỷ lệ cược cao mà đồng thời đọc vào cùng một tệp sẽ làm chậm hoạt động rất nhiều. Có một đĩa đơn để đọc từ và bạn muốn thực hiện truy cập hạt rất tốt đến những nơi khác nhau, với đồng bộ hóa. –

Trả lời

4

Cách thích hợp để thực hiện việc này sẽ khóa tệp, điều này sẽ ngăn tất cả các quá trình khác sử dụng nó. Xem Wikipedia: File locking. Điều này có thể là quá chậm đối với bạn, bởi vì bạn chỉ đọc một dòng tại một thời điểm. Nhưng nếu bạn đang đọc ví dụ 1000 hoặc 10000 dòng trong mỗi cuộc gọi hàm, nó có thể là cách tốt nhất để thực hiện nó.

Nếu không có quy trình nào khác truy cập tệp và chỉ đủ các chủ đề khác không truy cập được, bạn có thể sử dụng mutex mà bạn khóa khi bạn truy cập tệp.

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

Một cách khác để thực hiện chương trình của bạn có thể tạo một chuỗi duy nhất đang đọc đường vào bộ nhớ mọi lúc và các chủ đề khác sẽ yêu cầu một dòng từ lớp lưu trữ chúng. Bạn sẽ cần một cái gì đó như thế này:

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

Cảm ơn sự giúp đỡ của bạn! Tôi đã thử nghiệm với việc sử dụng mutex trong ví dụ đầu tiên vì nó dễ thực hiện nhanh hơn. Nó đọc tập tin một cách chính xác, và đưa ra một tốc độ đáng chú ý từ 1 lõi đến 2 lõi, nhưng phẳng sau đó. Tôi tưởng tượng các ổ khóa từ 3 chủ đề đang làm chậm nó xuống. Tôi tưởng tượng kết quả thứ hai sẽ có khả năng mở rộng hơn và tôi sẽ thực hiện điều đó vào một ngày sau đó. Cảm ơn một lần nữa! – tuchfarber

Các vấn đề liên quan