Linux環境下,多執行緒統計txt檔案中的單詞詞頻
阿新 • • 發佈:2021-11-09
#include <thread> #include <cstdio> #include <iostream> #include <cstdlib> #include <cctype> #include <mutex> #include <condition_variable> #include <algorithm> #include <unordered_set> #include <unordered_map> #include <vector> #include <atomic> #include <fstream> using namespace std; typedef pair<string, int> PSI; class Source {// 用於給互斥變數加鎖 public: unordered_map<string, int> mapWords; mutex m; unordered_set<string> specialWords;// 儲存需要排除在外的單詞(例如代詞、介詞、冠詞等) } source; atomic_int wordsCount;// 原子整型變數,用於統計單詞總數,並且會自動實現互斥訪問 vector<PSI> vecWords;// 實現詞頻排序 bool compare(const PSI& a, const PSI& b) {// 自定義排序規則 return a.second > b.second; } void countWords(char* fileName) {// 統計一個檔案中的單詞 FILE *inputFile = fopen((const char *)fileName, "r"); if (inputFile == NULL) { puts("No input file"); exit(0); } while (true) { char ch; string str = ""; while ((ch = fgetc(inputFile)) != EOF) { if (!isalpha(ch) && str.size() == 0) {// 讀到的字元不為字母,且現有字串長度為0,則直接跳過 continue; } else if (!isalpha(ch) && str.size() > 0)// 同上,但是字串長度不為0,現有的字串是一個完整的單詞了 break; str += tolower(ch);// 正常讀入了一個字元,就新增到臨時字串中 } if (ch == EOF) break; else { unique_lock<mutex> lck(source.m);// 對儲存佇列加鎖 wordsCount++; if (!source.specialWords.count(str)) { source.mapWords[str]++;// 將讀入的單詞加入到統計集 } lck.unlock();// 解鎖 } } fclose(inputFile); } void fixSpecialWords() { ifstream in("./wordSet.txt");// wordSet.txt就是儲存的需要排除在外的單詞 string str; if (in) while (getline(in, str)) source.specialWords.insert(str); else puts("read error"); } void showResult() {// 輸出結果 cout << "Number of input words: " << wordsCount << endl; for (auto it : source.mapWords) vecWords.push_back(it); sort(vecWords.begin(), vecWords.end(), compare); int cnt = 0; if (vecWords.size() >= 10) { cnt = vecWords[9].second; for (auto it : vecWords) { if (it.second < cnt) break; cout << it.first << " : " << it.second << endl; } } else { for (auto it : vecWords) cout << it.first << " : " << it.second << endl; } } int main(int argc, char *argv[]) { thread th[100]; fixSpecialWords(); for (int i = 1; i < argc; i++)// 將要進行統計的檔名作為引數今傳入程式 th[i] = thread(countWords, argv[i]); for (int i = 1; i < argc; i++) th[i].join(); showResult(); return 0; }
c++的main函式中argc 是argument count的縮寫表示傳入main函式中的引數個數,包括這個程式本身。argv 是 argument vector的縮寫表示傳入main函式中的引數列表,其中argv[0]表示這個程式的名字,argv[0]指向程式執行時的全路徑名;argv[1] 指向程式在命令列中執行程式名後的第一個字串;argv[2] 指向程式在命令列中執行程式名後的第二個字串;以此類推直到argv[argc]......
如圖tmux中,左邊是單執行緒統計的結果,右邊是多執行緒統計的結果;通過time函式我們可以看到,單執行緒是快於多執行緒的,並且多執行緒系統用時遠高於單執行緒,因為我們的設計思路是一個執行緒統計一個檔案中的單詞數,所以如果輸入檔案數越多,執行緒之間上下文切換的系統消耗就越多。所以可以設想一下,如果輸入檔案達到上百個時,多執行緒和單執行緒的結果是相同的,但是多執行緒無論是時間還是系統的消耗都是極大高於單執行緒的